activerecord-import 2.1.0 → 2.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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/README.markdown +9 -9
  4. data/lib/activerecord-import/active_record/adapters/mysql2_proxy_adapter.rb +8 -0
  5. data/lib/activerecord-import/active_record/adapters/postgresql_proxy_adapter.rb +8 -0
  6. data/lib/activerecord-import/active_record/adapters/sqlite3_proxy_adapter.rb +8 -0
  7. data/lib/activerecord-import/active_record/adapters/trilogy_proxy_adapter.rb +8 -0
  8. data/lib/activerecord-import/adapters/active_record_proxy_adapter.rb +19 -0
  9. data/lib/activerecord-import/adapters/mysql2_proxy_adapter.rb +9 -0
  10. data/lib/activerecord-import/adapters/mysql_adapter.rb +10 -3
  11. data/lib/activerecord-import/adapters/postgresql_adapter.rb +1 -1
  12. data/lib/activerecord-import/adapters/postgresql_proxy_adapter.rb +9 -0
  13. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +1 -1
  14. data/lib/activerecord-import/adapters/sqlite3_proxy_adapter.rb +9 -0
  15. data/lib/activerecord-import/adapters/trilogy_proxy_adapter.rb +9 -0
  16. data/lib/activerecord-import/base.rb +2 -2
  17. data/lib/activerecord-import/import.rb +243 -211
  18. data/lib/activerecord-import/version.rb +1 -1
  19. metadata +13 -200
  20. data/.github/workflows/test.yaml +0 -161
  21. data/.gitignore +0 -37
  22. data/.rubocop.yml +0 -118
  23. data/.rubocop_todo.yml +0 -30
  24. data/Brewfile +0 -5
  25. data/Dockerfile +0 -23
  26. data/Gemfile +0 -63
  27. data/Rakefile +0 -73
  28. data/activerecord-import.gemspec +0 -28
  29. data/benchmarks/README +0 -32
  30. data/benchmarks/benchmark.rb +0 -72
  31. data/benchmarks/lib/base.rb +0 -143
  32. data/benchmarks/lib/cli_parser.rb +0 -111
  33. data/benchmarks/lib/float.rb +0 -17
  34. data/benchmarks/lib/mysql2_benchmark.rb +0 -21
  35. data/benchmarks/lib/output_to_csv.rb +0 -21
  36. data/benchmarks/lib/output_to_html.rb +0 -66
  37. data/benchmarks/models/test_innodb.rb +0 -5
  38. data/benchmarks/models/test_memory.rb +0 -5
  39. data/benchmarks/models/test_myisam.rb +0 -5
  40. data/benchmarks/schema/mysql2_schema.rb +0 -18
  41. data/docker-compose.yml +0 -34
  42. data/gemfiles/5.2.gemfile +0 -4
  43. data/gemfiles/6.0.gemfile +0 -4
  44. data/gemfiles/6.1.gemfile +0 -4
  45. data/gemfiles/7.0.gemfile +0 -4
  46. data/gemfiles/7.1.gemfile +0 -3
  47. data/gemfiles/7.2.gemfile +0 -3
  48. data/gemfiles/8.0.gemfile +0 -3
  49. data/test/adapters/jdbcmysql.rb +0 -3
  50. data/test/adapters/jdbcpostgresql.rb +0 -3
  51. data/test/adapters/jdbcsqlite3.rb +0 -3
  52. data/test/adapters/makara_postgis.rb +0 -3
  53. data/test/adapters/mysql2.rb +0 -3
  54. data/test/adapters/mysql2_makara.rb +0 -3
  55. data/test/adapters/mysql2_proxy.rb +0 -3
  56. data/test/adapters/mysql2spatial.rb +0 -3
  57. data/test/adapters/postgis.rb +0 -3
  58. data/test/adapters/postgresql.rb +0 -3
  59. data/test/adapters/postgresql_makara.rb +0 -3
  60. data/test/adapters/postgresql_proxy.rb +0 -3
  61. data/test/adapters/seamless_database_pool.rb +0 -3
  62. data/test/adapters/spatialite.rb +0 -3
  63. data/test/adapters/sqlite3.rb +0 -3
  64. data/test/adapters/trilogy.rb +0 -11
  65. data/test/database.yml.sample +0 -65
  66. data/test/github/database.yml +0 -78
  67. data/test/import_test.rb +0 -970
  68. data/test/jdbcmysql/import_test.rb +0 -7
  69. data/test/jdbcpostgresql/import_test.rb +0 -6
  70. data/test/jdbcsqlite3/import_test.rb +0 -6
  71. data/test/makara_postgis/import_test.rb +0 -10
  72. data/test/models/account.rb +0 -5
  73. data/test/models/alarm.rb +0 -4
  74. data/test/models/animal.rb +0 -8
  75. data/test/models/author.rb +0 -9
  76. data/test/models/bike_maker.rb +0 -10
  77. data/test/models/book.rb +0 -18
  78. data/test/models/car.rb +0 -5
  79. data/test/models/card.rb +0 -5
  80. data/test/models/chapter.rb +0 -6
  81. data/test/models/composite_book.rb +0 -19
  82. data/test/models/composite_chapter.rb +0 -12
  83. data/test/models/customer.rb +0 -18
  84. data/test/models/deck.rb +0 -8
  85. data/test/models/dictionary.rb +0 -6
  86. data/test/models/discount.rb +0 -5
  87. data/test/models/end_note.rb +0 -6
  88. data/test/models/group.rb +0 -5
  89. data/test/models/order.rb +0 -17
  90. data/test/models/playing_card.rb +0 -4
  91. data/test/models/promotion.rb +0 -5
  92. data/test/models/question.rb +0 -5
  93. data/test/models/rule.rb +0 -5
  94. data/test/models/tag.rb +0 -12
  95. data/test/models/tag_alias.rb +0 -11
  96. data/test/models/topic.rb +0 -31
  97. data/test/models/user.rb +0 -5
  98. data/test/models/user_token.rb +0 -6
  99. data/test/models/vendor.rb +0 -9
  100. data/test/models/widget.rb +0 -33
  101. data/test/mysql2/import_test.rb +0 -7
  102. data/test/mysql2_makara/import_test.rb +0 -8
  103. data/test/mysql2_proxy/import_test.rb +0 -6
  104. data/test/mysqlspatial2/import_test.rb +0 -8
  105. data/test/postgis/import_test.rb +0 -10
  106. data/test/postgresql/import_test.rb +0 -6
  107. data/test/postgresql_proxy/import_test.rb +0 -6
  108. data/test/schema/generic_schema.rb +0 -230
  109. data/test/schema/jdbcpostgresql_schema.rb +0 -3
  110. data/test/schema/mysql2_schema.rb +0 -21
  111. data/test/schema/postgis_schema.rb +0 -3
  112. data/test/schema/postgresql_schema.rb +0 -94
  113. data/test/schema/sqlite3_schema.rb +0 -15
  114. data/test/schema/version.rb +0 -12
  115. data/test/sqlite3/import_test.rb +0 -6
  116. data/test/support/active_support/test_case_extensions.rb +0 -73
  117. data/test/support/assertions.rb +0 -75
  118. data/test/support/factories.rb +0 -66
  119. data/test/support/generate.rb +0 -31
  120. data/test/support/mysql/import_examples.rb +0 -97
  121. data/test/support/postgresql/import_examples.rb +0 -642
  122. data/test/support/shared_examples/on_duplicate_key_ignore.rb +0 -45
  123. data/test/support/shared_examples/on_duplicate_key_update.rb +0 -437
  124. data/test/support/shared_examples/recursive_import.rb +0 -352
  125. data/test/support/sqlite3/import_examples.rb +0 -232
  126. data/test/synchronize_test.rb +0 -43
  127. data/test/test_helper.rb +0 -91
  128. data/test/trilogy/import_test.rb +0 -7
  129. data/test/value_sets_bytes_parser_test.rb +0 -106
  130. data/test/value_sets_records_parser_test.rb +0 -34
data/Gemfile DELETED
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- gemspec
6
-
7
- version = ENV['AR_VERSION'].to_f
8
-
9
- mysql2_version = '0.4.0'
10
- mysql2_version = '0.5.0' if version >= 6.1
11
- mysql2_version = '0.5.6' if version >= 8.0
12
- sqlite3_version = '1.3.0'
13
- sqlite3_version = '1.4.0' if version >= 6.0
14
- sqlite3_version = '2.2.0' if version >= 8.0
15
- pg_version = '0.9'
16
- pg_version = '1.1' if version >= 6.1
17
- pg_version = '1.5' if version >= 8.0
18
-
19
- group :development, :test do
20
- gem 'rubocop'
21
- gem 'rake'
22
- end
23
-
24
- # Database Adapters
25
- platforms :ruby do
26
- gem "mysql2", "~> #{mysql2_version}"
27
- gem "pg", "~> #{pg_version}"
28
- gem "sqlite3", "~> #{sqlite3_version}"
29
- # seamless_database_pool requires Ruby ~> 2.0
30
- gem "seamless_database_pool", "~> 1.0.20" if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.0.0')
31
- gem "trilogy" if version >= 6.0
32
- if version >= 6.0 && version <= 7.0
33
- gem "activerecord-trilogy-adapter"
34
- end
35
- end
36
-
37
- platforms :jruby do
38
- gem "jdbc-mysql"
39
- gem "jdbc-postgres"
40
- gem "activerecord-jdbcsqlite3-adapter"
41
- gem "activerecord-jdbcmysql-adapter"
42
- gem "activerecord-jdbcpostgresql-adapter"
43
- end
44
-
45
- # Support libs
46
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0.0")
47
- gem "factory_bot"
48
- else
49
- gem "factory_bot", "~> 5", "< 6.4.5"
50
- end
51
- gem "timecop"
52
- gem "chronic"
53
- gem "mocha", "~> 2.1.0"
54
-
55
- # Debugging
56
- platforms :ruby do
57
- gem "pry-byebug"
58
- gem "pry", "~> 0.14.0"
59
- end
60
-
61
- gem "minitest"
62
-
63
- eval_gemfile File.expand_path("../gemfiles/#{version}.gemfile", __FILE__)
data/Rakefile DELETED
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler"
4
- Bundler.setup
5
-
6
- require 'rake'
7
- require 'rake/testtask'
8
-
9
- namespace :display do
10
- task :notice do
11
- puts
12
- puts "To run tests you must supply the adapter, see rake -T for more information."
13
- puts
14
- end
15
- end
16
- task default: ["display:notice"]
17
-
18
- ADAPTERS = %w(
19
- mysql2
20
- mysql2_makara
21
- mysql2spatial
22
- mysql2_proxy
23
- jdbcmysql
24
- jdbcsqlite3
25
- jdbcpostgresql
26
- postgresql
27
- postgresql_makara
28
- postgresql_proxy
29
- postgis
30
- makara_postgis
31
- sqlite3
32
- spatialite
33
- seamless_database_pool
34
- trilogy
35
- ).freeze
36
- ADAPTERS.each do |adapter|
37
- namespace :test do
38
- desc "Runs #{adapter} database tests."
39
- Rake::TestTask.new(adapter) do |t|
40
- # FactoryBot has an issue with warnings, so turn off, so noisy
41
- # t.warning = true
42
- t.test_files = FileList["test/adapters/#{adapter}.rb", "test/*_test.rb", "test/active_record/*_test.rb", "test/#{adapter}/**/*_test.rb"]
43
- end
44
- task adapter
45
- end
46
- end
47
-
48
- begin
49
- require 'rcov/rcovtask'
50
- adapter = ENV['ARE_DB']
51
- Rcov::RcovTask.new do |test|
52
- test.libs << 'test'
53
- test.pattern = ["test/adapters/#{adapter}.rb", "test/*_test.rb", "test/#{adapter}/**/*_test.rb"]
54
- test.verbose = true
55
- end
56
- rescue LoadError
57
- task :rcov do
58
- abort "RCov is not available. In order to run rcov, you must: sudo gem install rcov"
59
- end
60
- end
61
-
62
- require 'rdoc/task'
63
- Rake::RDocTask.new do |rdoc|
64
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
65
-
66
- rdoc.rdoc_dir = 'rdoc'
67
- rdoc.title = "activerecord-import #{version}"
68
- rdoc.rdoc_files.include('README*')
69
- rdoc.rdoc_files.include('lib/**/*.rb')
70
- end
71
-
72
- require 'rubocop/rake_task'
73
- RuboCop::RakeTask.new
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require File.expand_path('../lib/activerecord-import/version', __FILE__)
4
-
5
- Gem::Specification.new do |gem|
6
- gem.authors = ["Zach Dennis"]
7
- gem.email = ["zach.dennis@gmail.com"]
8
- gem.summary = "Bulk insert extension for ActiveRecord"
9
- gem.description = "A library for bulk inserting data using ActiveRecord."
10
- gem.homepage = "https://github.com/zdennis/activerecord-import"
11
- gem.license = "MIT"
12
-
13
- gem.metadata = {
14
- "changelog_uri" => "https://github.com/zdennis/activerecord-import/blob/master/CHANGELOG.md"
15
- }
16
-
17
- gem.files = `git ls-files`.split($\)
18
- gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
19
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
- gem.name = "activerecord-import"
21
- gem.require_paths = ["lib"]
22
- gem.version = ActiveRecord::Import::VERSION
23
-
24
- gem.required_ruby_version = ">= 2.4.0"
25
-
26
- gem.add_runtime_dependency "activerecord", ">= 4.2"
27
- gem.add_development_dependency "rake"
28
- end
data/benchmarks/README DELETED
@@ -1,32 +0,0 @@
1
- To run the benchmarks, from within the benchmarks run:
2
- ruby benchmark.rb [options]
3
-
4
- The following options are supported:
5
- --adapter [String] The database adapter to use. IE: mysql, postgresql, oracle
6
-
7
- --do-not-delete By default all records in the benchmark tables will be deleted at the end of the benchmark. This flag indicates not to delete the benchmark data.
8
- --num [Integer] The number of objects to benchmark. (Required!)
9
- --table-type [String] The table type to test. This can be used multiple times. By default it is all table types.
10
- --to-csv [String] Print results in a CSV file format
11
- --to-html [String] Print results in HTML format (String filename must be supplied)
12
-
13
- See "ruby benchmark.rb -h" for the complete listing of options.
14
-
15
- EXAMPLES
16
- --------
17
- To output to html format:
18
- ruby benchmark.rb --adapter=mysql2 --to-html=results.html
19
-
20
- To output to csv format:
21
- ruby benchmark.rb --adapter=mysql2 --to-csv=results.csv
22
-
23
- LIMITATIONS
24
- -----------
25
- Currently MySQL is the only supported adapter to benchmark.
26
-
27
- AUTHOR
28
- ------
29
- Zach Dennis
30
- zach.dennis@gmail.com
31
- http://www.continuousthinking.com
32
-
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'pathname'
4
- require "fileutils"
5
- require "active_record"
6
- require "active_record/base"
7
-
8
- benchmark_dir = File.dirname(__FILE__)
9
-
10
- $LOAD_PATH.unshift('.')
11
-
12
- # Get the gem into the load path
13
- $LOAD_PATH.unshift(File.join(benchmark_dir, '..', 'lib'))
14
-
15
- # Load the benchmark files
16
- Dir[File.join( benchmark_dir, 'lib', '*.rb' )].sort.each { |f| require f }
17
-
18
- # Parse the options passed in via the command line
19
- options = BenchmarkOptionParser.parse( ARGV )
20
-
21
- FileUtils.mkdir_p 'log'
22
- ActiveRecord::Base.configurations["test"] = YAML.load_file(File.join(benchmark_dir, "../test/database.yml"))[options.adapter]
23
- ActiveRecord::Base.logger = Logger.new("log/test.log")
24
- ActiveRecord::Base.logger.level = Logger::DEBUG
25
- if ActiveRecord.respond_to?(:default_timezone)
26
- ActiveRecord.default_timezone = :utc
27
- else
28
- ActiveRecord::Base.default_timezone = :utc
29
- end
30
-
31
- require "activerecord-import"
32
- ActiveRecord::Base.establish_connection(:test)
33
-
34
- ActiveSupport::Notifications.subscribe(/active_record.sql/) do |_, _, _, _, hsh|
35
- ActiveRecord::Base.logger.info hsh[:sql]
36
- end
37
-
38
- # Load base/generic schema
39
- require File.join(benchmark_dir, "../test/schema/version")
40
- require File.join(benchmark_dir, "../test/schema/generic_schema")
41
- adapter_schema = File.join(benchmark_dir, "schema/#{options.adapter}_schema.rb")
42
- require adapter_schema if File.exist?(adapter_schema)
43
-
44
- Dir["#{File.dirname(__FILE__)}/models/*.rb"].sort.each { |file| require file }
45
-
46
- require File.join( benchmark_dir, 'lib', "#{options.adapter}_benchmark" )
47
- table_types = if options.benchmark_all_types
48
- ["all"]
49
- else
50
- options.table_types.keys
51
- end
52
-
53
- letter = options.adapter[0].chr
54
- clazz_str = letter.upcase + options.adapter[1..].downcase
55
- clazz = Object.const_get( "#{clazz_str}Benchmark" )
56
-
57
- benchmarks = []
58
- options.number_of_objects.each do |num|
59
- benchmarks << (benchmark = clazz.new)
60
- benchmark.send( "benchmark", table_types, num )
61
- end
62
-
63
- options.outputs.each do |output|
64
- format = output.format.downcase
65
- output_module = Object.const_get( "OutputTo#{format.upcase}" )
66
- benchmarks.each do |benchmark|
67
- output_module.output_results( output.filename, benchmark.results )
68
- end
69
- end
70
-
71
- puts
72
- puts "Done with benchmark!"
@@ -1,143 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class BenchmarkBase
4
- attr_reader :results
5
-
6
- # The main benchmark method dispatcher. This dispatches the benchmarks
7
- # to actual benchmark_xxxx methods.
8
- #
9
- # == PARAMETERS
10
- # * table_types - an array of table types to benchmark
11
- # * num - the number of record insertions to test
12
- def benchmark( table_types, num )
13
- array_of_cols_and_vals = build_array_of_cols_and_vals( num )
14
- table_types.each do |table_type|
15
- send( "benchmark_#{table_type}", array_of_cols_and_vals )
16
- end
17
- end
18
-
19
- # Returns a struct which contains two attritues, +description+ and +tms+ after performing an
20
- # actual benchmark.
21
- #
22
- # == PARAMETERS
23
- # * description - the description of the block that is getting benchmarked
24
- # * blk - the block of code to benchmark
25
- #
26
- # == RETURNS
27
- # A struct object with the following attributes:
28
- # * description - the description of the benchmark ran
29
- # * tms - a Benchmark::Tms containing the results of the benchmark
30
-
31
- BmStruct = Struct.new( :description, :tms, :failed, keyword_init: true )
32
-
33
- def bm( description, &block )
34
- tms = nil
35
- puts "Benchmarking #{description}"
36
-
37
- Benchmark.bm { |x| tms = x.report(&block) }
38
- delete_all
39
- failed = false
40
-
41
- BmStruct.new( description: description, tms: tms, failed: failed )
42
- end
43
-
44
- # Given a model class (ie: Topic), and an array of columns and value sets
45
- # this will perform all of the benchmarks necessary for this library.
46
- #
47
- # == PARAMETERS
48
- # * model_clazz - the model class to benchmark (ie: Topic)
49
- # * array_of_cols_and_vals - an array of column identifiers and value sets
50
- #
51
- # == RETURNS
52
- # returns true
53
- def bm_model( model_clazz, array_of_cols_and_vals )
54
- puts
55
- puts "------ Benchmarking #{model_clazz.name} -------"
56
-
57
- cols, vals = array_of_cols_and_vals
58
- num_inserts = vals.size
59
-
60
- # add a new result group for this particular benchmark
61
- group = []
62
- @results << group
63
-
64
- description = "#{model_clazz.name}.create (#{num_inserts} records)"
65
- group << bm( description ) do
66
- vals.each do |values|
67
- model_clazz.create create_hash_for_cols_and_vals( cols, values )
68
- end
69
- end
70
-
71
- description = "#{model_clazz.name}.import(column, values) for #{num_inserts} records with validations"
72
- group << bm( description ) { model_clazz.import cols, vals, validate: true }
73
-
74
- description = "#{model_clazz.name}.import(columns, values) for #{num_inserts} records without validations"
75
- group << bm( description ) { model_clazz.import cols, vals, validate: false }
76
-
77
- models = []
78
- array_of_attrs = []
79
-
80
- vals.each do |arr|
81
- array_of_attrs << (attrs = {})
82
- arr.each_with_index { |value, i| attrs[cols[i]] = value }
83
- end
84
- array_of_attrs.each { |attrs| models << model_clazz.new(attrs) }
85
-
86
- description = "#{model_clazz.name}.import(models) for #{num_inserts} records with validations"
87
- group << bm( description ) { model_clazz.import models, validate: true }
88
-
89
- description = "#{model_clazz.name}.import(models) for #{num_inserts} records without validations"
90
- group << bm( description ) { model_clazz.import models, validate: false }
91
-
92
- true
93
- end
94
-
95
- # Returns a two element array composing of an array of columns and an array of
96
- # value sets given the passed +num+.
97
- #
98
- # === What is a value set?
99
- # A value set is an array of arrays. Each child array represents an array of value sets
100
- # for a given row of data.
101
- #
102
- # For example, say we wanted to represent an insertion of two records:
103
- # column_names = [ 'id', 'name', 'description' ]
104
- # record1 = [ 1, 'John Doe', 'A plumber' ]
105
- # record2 = [ 2, 'John Smith', 'A painter' ]
106
- # value_set [ record1, record2 ]
107
- #
108
- # == PARAMETER
109
- # * num - the number of records to create
110
- def build_array_of_cols_and_vals( num )
111
- cols = [:my_name, :description]
112
- value_sets = []
113
- num.times { |i| value_sets << ["My Name #{i}", "My Description #{i}"] }
114
- [cols, value_sets]
115
- end
116
-
117
- # Returns a hash of column identifier to value mappings giving the passed in
118
- # value array.
119
- #
120
- # Example:
121
- # cols = [ 'id', 'name', 'description' ]
122
- # values = [ 1, 'John Doe', 'A plumber' ]
123
- # hsh = create_hash_for_cols_and_vals( cols, values )
124
- # # hsh => { 'id'=>1, 'name'=>'John Doe', 'description'=>'A plumber' }
125
- def create_hash_for_cols_and_vals( cols, vals )
126
- h = {}
127
- cols.zip( vals ) { |col, val| h[col] = val }
128
- h
129
- end
130
-
131
- # Deletes all records from all ActiveRecord subclasses
132
- def delete_all
133
- ActiveRecord::Base.send( :subclasses ).each do |subclass|
134
- if subclass.table_exists? && subclass.respond_to?(:delete_all)
135
- subclass.delete_all
136
- end
137
- end
138
- end
139
-
140
- def initialize # :nodoc:
141
- @results = []
142
- end
143
- end
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'optparse'
4
-
5
- #
6
- # == PARAMETERS
7
- # * a - database adapter. ie: mysql, postgresql, oracle, etc.
8
- # * n - number of objects to test with. ie: 1, 100, 1000, etc.
9
- # * t - the table types to test. ie: myisam, innodb, memory, temporary, etc.
10
- #
11
- module BenchmarkOptionParser
12
- BANNER = "Usage: ruby #{$0} [options]\nSee ruby #{$0} -h for more options.".freeze
13
-
14
- def self.print_banner
15
- puts BANNER
16
- end
17
-
18
- def self.print_banner!
19
- print_banner
20
- exit
21
- end
22
-
23
- def self.print_options( options )
24
- puts "Benchmarking the following options:"
25
- puts " Database adapter: #{options.adapter}"
26
- puts " Number of objects: #{options.number_of_objects}"
27
- puts " Table types:"
28
- print_valid_table_types( options, prefix: " " )
29
- end
30
-
31
- # TODO: IMPLEMENT THIS
32
- def self.print_valid_table_types( options, hsh = { prefix: '' } )
33
- if !options.table_types.keys.empty?
34
- options.table_types.keys.sort.each { |type| puts hsh[:prefix].to_s + type.to_s }
35
- else
36
- puts 'No table types defined.'
37
- end
38
- end
39
-
40
- OptionsStruct = Struct.new( :adapter, :table_types, :delete_on_finish, :number_of_objects, :outputs,
41
- :benchmark_all_types, keyword_init: true )
42
- OutputStruct = Struct.new( :format, :filename, keyword_init: true )
43
- def self.parse( args )
44
- options = OptionsStruct.new(
45
- adapter: 'mysql2',
46
- table_types: {},
47
- delete_on_finish: true,
48
- number_of_objects: [],
49
- outputs: []
50
- )
51
-
52
- opt_parser = OptionParser.new do |opts|
53
- opts.banner = BANNER
54
-
55
- # parse the database adapter
56
- opts.on( "a", "--adapter [String]",
57
- "The database adapter to use. IE: mysql, postgresql, oracle" ) do |arg|
58
- options.adapter = arg
59
- end
60
-
61
- # parse do_not_delete flag
62
- opts.on( "d", "--do-not-delete",
63
- "By default all records in the benchmark tables will be deleted at the end of the benchmark. " \
64
- "This flag indicates not to delete the benchmark data." ) do |_|
65
- options.delete_on_finish = false
66
- end
67
-
68
- # parse the number of row objects to test
69
- opts.on( "n", "--num [Integer]",
70
- "The number of objects to benchmark." ) do |arg|
71
- options.number_of_objects << arg.to_i
72
- end
73
-
74
- # parse the table types to test
75
- opts.on( "t", "--table-type [String]",
76
- "The table type to test. This can be used multiple times." ) do |arg|
77
- if arg =~ /^all$/
78
- options.table_types['all'] = options.benchmark_all_types = true
79
- else
80
- options.table_types[arg] = true
81
- end
82
- end
83
-
84
- # print results in CSV format
85
- opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
86
- options.outputs << OutputStruct.new( format: 'csv', filename: filename)
87
- end
88
-
89
- # print results in HTML format
90
- opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
91
- options.outputs << OutputStruct.new( format: 'html', filename: filename )
92
- end
93
- end # end opt.parse!
94
-
95
- begin
96
- opt_parser.parse!( args )
97
- if options.table_types.empty?
98
- options.table_types['all'] = options.benchmark_all_types = true
99
- end
100
- rescue Exception
101
- print_banner!
102
- end
103
-
104
- options.number_of_objects = [1000] if options.number_of_objects.empty?
105
- options.outputs = [OutputStruct.new( format: 'html', filename: 'benchmark.html')] if options.outputs.empty?
106
-
107
- print_options( options )
108
-
109
- options
110
- end
111
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Taken from http://www.programmingishard.com/posts/show/128
4
- # Posted by rbates
5
- class Float
6
- def round_to(x)
7
- (self * 10**x).round.to_f / 10**x
8
- end
9
-
10
- def ceil_to(x)
11
- (self * 10**x).ceil.to_f / 10**x
12
- end
13
-
14
- def floor_to(x)
15
- (self * 10**x).floor.to_f / 10**x
16
- end
17
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Mysql2Benchmark < BenchmarkBase
4
- def benchmark_all( array_of_cols_and_vals )
5
- methods = self.methods.find_all { |m| m =~ /benchmark_/ }
6
- methods.delete_if { |m| m =~ /benchmark_(all|model)/ }
7
- methods.each { |method| send( method, array_of_cols_and_vals ) }
8
- end
9
-
10
- def benchmark_myisam( array_of_cols_and_vals )
11
- bm_model( TestMyISAM, array_of_cols_and_vals )
12
- end
13
-
14
- def benchmark_innodb( array_of_cols_and_vals )
15
- bm_model( TestInnoDb, array_of_cols_and_vals )
16
- end
17
-
18
- def benchmark_memory( array_of_cols_and_vals )
19
- bm_model( TestMemory, array_of_cols_and_vals )
20
- end
21
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'csv'
4
-
5
- module OutputToCSV
6
- def self.output_results( filename, results )
7
- CSV.open( filename, 'w' ) do |csv|
8
- # Iterate over each result set, which contains many results
9
- results.each do |result_set|
10
- columns = []
11
- times = []
12
- result_set.each do |result|
13
- columns << result.description
14
- times << result.tms.real
15
- end
16
- csv << columns
17
- csv << times
18
- end
19
- end
20
- end
21
- end
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'erb'
4
-
5
- module OutputToHTML
6
- TEMPLATE_HEADER = <<"EOT"
7
- <div>
8
- All times are rounded to the nearest thousandth for display purposes. Speedups next to each time are computed
9
- before any rounding occurs. Also, all speedup calculations are computed by comparing a given time against
10
- the very first column (which is always the default ActiveRecord::Base.create method.
11
- </div>
12
- EOT
13
-
14
- TEMPLATE = <<"EOT"
15
- <style>
16
- td#benchmarkTitle {
17
- border: 1px solid black;
18
- padding: 2px;
19
- font-size: 0.8em;
20
- background-color: black;
21
- color: white;
22
- }
23
- td#benchmarkCell {
24
- border: 1px solid black;
25
- padding: 2px;
26
- font-size: 0.8em;
27
- }
28
- </style>
29
- <table>
30
- <tr>
31
- <% columns.each do |col| %>
32
- <td id="benchmarkTitle"><%= col %></td>
33
- <% end %>
34
- </tr>
35
- <tr>
36
- <% times.each do |time| %>
37
- <td id="benchmarkCell"><%= time %></td>
38
- <% end %>
39
- </tr>
40
- <tr><td>&nbsp;</td></tr>
41
- </table>
42
- EOT
43
-
44
- def self.output_results( filename, results )
45
- html = ''
46
- results.each do |result_set|
47
- columns = []
48
- times = []
49
- result_set.each do |result|
50
- columns << result.description
51
- if result.failed
52
- times << "failed"
53
- else
54
- time = result.tms.real.round_to( 3 )
55
- speedup = ( result_set.first.tms.real / result.tms.real ).round
56
- times << (result == result_set.first ? time.to_s : "#{time} (#{speedup}x speedup)")
57
- end
58
- end
59
-
60
- template = ERB.new( TEMPLATE, 0, "%<>")
61
- html << template.result( binding )
62
- end
63
-
64
- File.open( filename, 'w' ) { |file| file.write( TEMPLATE_HEADER + html ) }
65
- end
66
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class TestInnoDb < ActiveRecord::Base
4
- self.table_name = 'test_innodb'
5
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class TestMemory < ActiveRecord::Base
4
- self.table_name = 'test_memory'
5
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class TestMyISAM < ActiveRecord::Base
4
- self.table_name = 'test_myisam'
5
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- ActiveRecord::Schema.define do
4
- create_table :test_myisam, options: 'ENGINE=MyISAM', force: true do |t|
5
- t.column :my_name, :string, null: false
6
- t.column :description, :string
7
- end
8
-
9
- create_table :test_innodb, options: 'ENGINE=InnoDb', force: true do |t|
10
- t.column :my_name, :string, null: false
11
- t.column :description, :string
12
- end
13
-
14
- create_table :test_memory, options: 'ENGINE=Memory', force: true do |t|
15
- t.column :my_name, :string, null: false
16
- t.column :description, :string
17
- end
18
- end