activerecord-import 0.12.0 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +49 -0
- data/.rubocop_todo.yml +36 -0
- data/.travis.yml +31 -7
- data/CHANGELOG.md +19 -0
- data/Gemfile +5 -2
- data/README.markdown +6 -1
- data/Rakefile +5 -2
- data/activerecord-import.gemspec +1 -1
- data/benchmarks/benchmark.rb +67 -68
- data/benchmarks/lib/base.rb +136 -137
- data/benchmarks/lib/cli_parser.rb +106 -107
- data/benchmarks/lib/mysql2_benchmark.rb +19 -21
- data/benchmarks/lib/output_to_csv.rb +2 -1
- data/benchmarks/lib/output_to_html.rb +8 -13
- data/benchmarks/schema/mysql_schema.rb +8 -8
- data/gemfiles/4.0.gemfile +1 -1
- data/gemfiles/4.1.gemfile +1 -1
- data/gemfiles/4.2.gemfile +1 -1
- data/gemfiles/5.0.gemfile +1 -1
- data/lib/activerecord-import.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +0 -1
- data/lib/activerecord-import/adapters/abstract_adapter.rb +9 -9
- data/lib/activerecord-import/adapters/mysql_adapter.rb +17 -17
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +20 -22
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +9 -9
- data/lib/activerecord-import/base.rb +3 -3
- data/lib/activerecord-import/import.rb +152 -131
- data/lib/activerecord-import/synchronize.rb +20 -20
- data/lib/activerecord-import/value_sets_parser.rb +7 -6
- data/lib/activerecord-import/version.rb +1 -1
- data/test/adapters/mysql2spatial.rb +1 -1
- data/test/adapters/postgis.rb +1 -1
- data/test/adapters/postgresql.rb +1 -1
- data/test/adapters/spatialite.rb +1 -1
- data/test/adapters/sqlite3.rb +1 -1
- data/test/import_test.rb +121 -70
- data/test/models/book.rb +5 -6
- data/test/models/chapter.rb +2 -2
- data/test/models/discount.rb +3 -0
- data/test/models/end_note.rb +2 -2
- data/test/models/promotion.rb +1 -1
- data/test/models/question.rb +1 -1
- data/test/models/rule.rb +2 -2
- data/test/models/topic.rb +3 -3
- data/test/models/widget.rb +1 -1
- data/test/postgis/import_test.rb +1 -1
- data/test/schema/generic_schema.rb +100 -96
- data/test/schema/mysql_schema.rb +5 -7
- data/test/sqlite3/import_test.rb +0 -2
- data/test/support/active_support/test_case_extensions.rb +12 -15
- data/test/support/assertions.rb +1 -1
- data/test/support/factories.rb +15 -16
- data/test/support/generate.rb +4 -4
- data/test/support/mysql/import_examples.rb +21 -21
- data/test/support/postgresql/import_examples.rb +83 -55
- data/test/support/shared_examples/on_duplicate_key_update.rb +23 -23
- data/test/synchronize_test.rb +2 -2
- data/test/test_helper.rb +6 -8
- data/test/value_sets_bytes_parser_test.rb +14 -17
- data/test/value_sets_records_parser_test.rb +6 -6
- metadata +7 -4
- data/test/travis/build.sh +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f525ceb164067e5f2c49042b1a8f3312eab016a
|
4
|
+
data.tar.gz: c9817adb82be93259525dc52a85b42bf7829d585
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 974e9a0491e43cd9a9a22e167f1b9dede5bcdececbb3d480c2b4edf2e293e50c0cf3e85f39b4d10f624c541a0651db5de2f85bad0d5ca7142c4de28017e1809f
|
7
|
+
data.tar.gz: 4e31a0c10174ba285b08d47abbac06c2089c62488c5f3775d24c6b993b4c7bd465d051e5238e6df511da6ad8b152f47f5827b41cf316d5e8713dc9bd2c64e9bc
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
Lint/EndAlignment:
|
4
|
+
AlignWith: variable
|
5
|
+
|
6
|
+
Metrics/AbcSize:
|
7
|
+
Enabled: false
|
8
|
+
|
9
|
+
Metrics/ClassLength:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Metrics/CyclomaticComplexity:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Metrics/LineLength:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Metrics/MethodLength:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Metrics/ModuleLength:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Metrics/PerceivedComplexity:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Style/AlignParameters:
|
28
|
+
EnforcedStyle: with_fixed_indentation
|
29
|
+
|
30
|
+
Style/ClassAndModuleChildren:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Style/Documentation:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Style/ElseAlignment:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Style/SpaceInsideParens:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
Style/SpecialGlobalVars:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Style/StringLiterals:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Style/TrailingCommaInLiteral:
|
49
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2016-03-17 18:14:55 -0700 using RuboCop version 0.38.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 2
|
10
|
+
Lint/HandleExceptions:
|
11
|
+
Exclude:
|
12
|
+
- 'lib/activerecord-import/base.rb'
|
13
|
+
- 'test/import_test.rb'
|
14
|
+
|
15
|
+
# Offense count: 2
|
16
|
+
Lint/RescueException:
|
17
|
+
Exclude:
|
18
|
+
- 'benchmarks/lib/cli_parser.rb'
|
19
|
+
- 'test/import_test.rb'
|
20
|
+
|
21
|
+
# Offense count: 4
|
22
|
+
# Cop supports --auto-correct.
|
23
|
+
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
|
24
|
+
Lint/UnusedMethodArgument:
|
25
|
+
Exclude:
|
26
|
+
- 'lib/activerecord-import/adapters/postgresql_adapter.rb'
|
27
|
+
- 'lib/activerecord-import/import.rb'
|
28
|
+
|
29
|
+
# Offense count: 2
|
30
|
+
# Cop supports --auto-correct.
|
31
|
+
# Configuration parameters: Keywords.
|
32
|
+
# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW
|
33
|
+
Style/CommentAnnotation:
|
34
|
+
Exclude:
|
35
|
+
- 'benchmarks/lib/cli_parser.rb'
|
36
|
+
- 'lib/activerecord-import/import.rb'
|
data/.travis.yml
CHANGED
@@ -1,20 +1,44 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
3
|
rvm:
|
4
|
-
- 2.2.
|
4
|
+
- 2.2.4
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
env:
|
7
|
+
global:
|
8
|
+
# https://github.com/discourse/discourse/blob/master/.travis.yml
|
9
|
+
- RUBY_GC_MALLOC_LIMIT=50000000
|
10
|
+
matrix:
|
11
|
+
- AR_VERSION=3.1
|
12
|
+
- AR_VERSION=3.2
|
13
|
+
- AR_VERSION=4.0
|
14
|
+
- AR_VERSION=4.1
|
15
|
+
- AR_VERSION=4.2
|
16
|
+
- AR_VERSION=5.0
|
8
17
|
|
9
|
-
|
18
|
+
matrix:
|
19
|
+
fast_finish: true
|
10
20
|
|
11
21
|
before_script:
|
12
22
|
- mysql -e 'create database activerecord_import_test;'
|
13
23
|
- psql -c 'create database activerecord_import_test;' -U postgres
|
14
24
|
- psql -U postgres -c "create extension postgis"
|
15
25
|
- cp test/travis/database.yml test/database.yml
|
16
|
-
|
17
|
-
|
26
|
+
|
27
|
+
addons:
|
28
|
+
apt:
|
29
|
+
sources:
|
30
|
+
- travis-ci/sqlite3
|
31
|
+
packages:
|
32
|
+
- sqlite3
|
18
33
|
|
19
34
|
script:
|
20
|
-
- test
|
35
|
+
- bundle exec rake test:mysql2
|
36
|
+
- bundle exec rake test:mysql2spatial
|
37
|
+
- bundle exec rake test:postgis
|
38
|
+
- bundle exec rake test:postgresql
|
39
|
+
- bundle exec rake test:seamless_database_pool
|
40
|
+
- bundle exec rake test:spatialite
|
41
|
+
- bundle exec rake test:sqlite3
|
42
|
+
- bundle exec rubocop
|
43
|
+
|
44
|
+
sudo: false
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
## Changes in 0.13.0
|
2
|
+
|
3
|
+
### New Features
|
4
|
+
|
5
|
+
* Addition of :batch_size option to control the number of rows to insert per INSERT statement. The default is the total number of records being inserted so there is a single INSERT statement. Thanks to @jkowens via \#245
|
6
|
+
|
7
|
+
* Addition `import!` which will raise an exception if a validation occurs. It will fail fast. Thanks to @jkowens via \#246
|
8
|
+
|
9
|
+
### Fixes
|
10
|
+
|
11
|
+
* Fixing issue with recursive import when utilizing the `:on_duplicate_key_update` option. The `on_duplicate_key_update` only applies to parent models at this time. Thanks to @yuri-karpovich for reporting and @jkowens for fixing via \#249
|
12
|
+
|
13
|
+
### Misc
|
14
|
+
|
15
|
+
* Refactoring of fetching and assigning attributes. Thanks to @jkownes via \#259
|
16
|
+
* Lots of code cleanup and addition of Rubocop linter. Thanks to @sferik via \#256 and \#250
|
17
|
+
* Resolving errors with the test suite when running against ActiveRecord 4.0 and 4.1. Thanks to @jkowens via \#262
|
18
|
+
* Cleaning up the TravisCI settings and packages. Thanks to @sferik via \#258 and \#251
|
19
|
+
|
1
20
|
## Changes in 0.12.0
|
2
21
|
|
3
22
|
### New Features
|
data/Gemfile
CHANGED
@@ -2,6 +2,10 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
group :development, :test do
|
6
|
+
gem 'rubocop', '~> 0.38.0'
|
7
|
+
end
|
8
|
+
|
5
9
|
# Database Adapters
|
6
10
|
platforms :ruby do
|
7
11
|
gem "mysql2", "~> 0.3.0"
|
@@ -22,7 +26,6 @@ gem "factory_girl", "~> 4.2.0"
|
|
22
26
|
gem "timecop"
|
23
27
|
gem "chronic"
|
24
28
|
|
25
|
-
|
26
29
|
# Debugging
|
27
30
|
platforms :jruby do
|
28
31
|
gem "ruby-debug-base", "= 0.10.4"
|
@@ -42,7 +45,7 @@ end
|
|
42
45
|
|
43
46
|
version = ENV['AR_VERSION'] || "4.2"
|
44
47
|
|
45
|
-
if version
|
48
|
+
if version >= "4.0"
|
46
49
|
gem "minitest"
|
47
50
|
else
|
48
51
|
gem "test-unit"
|
data/README.markdown
CHANGED
@@ -21,6 +21,10 @@ and then the reviews:
|
|
21
21
|
That would be about 4M SQL insert statements vs 3, which results in vastly improved performance. In our case, it converted
|
22
22
|
an 18 hour batch process to <2 hrs.
|
23
23
|
|
24
|
+
### Rails 5.0
|
25
|
+
|
26
|
+
Use activerecord-import 0.11.0 or higher.
|
27
|
+
|
24
28
|
### Rails 4.0
|
25
29
|
|
26
30
|
Use activerecord-import 0.4.0 or higher.
|
@@ -85,7 +89,8 @@ Zach Dennis (zach.dennis@gmail.com)
|
|
85
89
|
|
86
90
|
# Contributors
|
87
91
|
|
88
|
-
* Jordan Owens
|
92
|
+
* Jordan Owens (@jkowens)
|
93
|
+
* Erik Michaels-Ober (@sferik)
|
89
94
|
* Blythe Dunham
|
90
95
|
* Gabe da Silveira
|
91
96
|
* Henry Work
|
data/Rakefile
CHANGED
@@ -11,9 +11,9 @@ namespace :display do
|
|
11
11
|
puts
|
12
12
|
end
|
13
13
|
end
|
14
|
-
task :
|
14
|
+
task default: ["display:notice"]
|
15
15
|
|
16
|
-
ADAPTERS = %w(mysql2 jdbcmysql jdbcpostgresql postgresql sqlite3 seamless_database_pool mysql2spatial spatialite postgis)
|
16
|
+
ADAPTERS = %w(mysql2 jdbcmysql jdbcpostgresql postgresql sqlite3 seamless_database_pool mysql2spatial spatialite postgis).freeze
|
17
17
|
ADAPTERS.each do |adapter|
|
18
18
|
namespace :test do
|
19
19
|
desc "Runs #{adapter} database tests."
|
@@ -49,3 +49,6 @@ Rake::RDocTask.new do |rdoc|
|
|
49
49
|
rdoc.rdoc_files.include('README*')
|
50
50
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
51
|
end
|
52
|
+
|
53
|
+
require 'rubocop/rake_task'
|
54
|
+
RuboCop::RakeTask.new
|
data/activerecord-import.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
|
|
10
10
|
gem.license = "Ruby"
|
11
11
|
|
12
12
|
gem.files = `git ls-files`.split($\)
|
13
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
14
14
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
15
|
gem.name = "activerecord-import"
|
16
16
|
gem.require_paths = ["lib"]
|
data/benchmarks/benchmark.rb
CHANGED
@@ -1,68 +1,67 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
require "fileutils"
|
3
|
-
require "active_record"
|
4
|
-
|
5
|
-
benchmark_dir = File.dirname(__FILE__)
|
6
|
-
|
7
|
-
$LOAD_PATH.unshift('.')
|
8
|
-
|
9
|
-
# Get the gem into the load path
|
10
|
-
$LOAD_PATH.unshift(File.join(benchmark_dir, '..', 'lib'))
|
11
|
-
|
12
|
-
# Load the benchmark files
|
13
|
-
Dir[File.join( benchmark_dir, 'lib', '*.rb' )
|
14
|
-
|
15
|
-
# Parse the options passed in via the command line
|
16
|
-
options = BenchmarkOptionParser.parse( ARGV )
|
17
|
-
|
18
|
-
FileUtils.mkdir_p 'log'
|
19
|
-
ActiveRecord::Base.configurations["test"] = YAML.load_file(File.join(benchmark_dir, "../test/database.yml"))[options.adapter]
|
20
|
-
ActiveRecord::Base.logger = Logger.new("log/test.log")
|
21
|
-
ActiveRecord::Base.logger.level = Logger::DEBUG
|
22
|
-
ActiveRecord::Base.default_timezone = :utc
|
23
|
-
|
24
|
-
require "activerecord-import"
|
25
|
-
ActiveRecord::Base.establish_connection(:test)
|
26
|
-
|
27
|
-
ActiveSupport::Notifications.subscribe(/active_record.sql/) do |
|
28
|
-
ActiveRecord::Base.logger.info hsh[:sql]
|
29
|
-
end
|
30
|
-
|
31
|
-
# Load base/generic schema
|
32
|
-
require File.join(benchmark_dir, "../test/schema/version")
|
33
|
-
require File.join(benchmark_dir, "../test/schema/generic_schema")
|
34
|
-
adapter_schema = File.join(benchmark_dir, "schema/#{options.adapter}_schema.rb")
|
35
|
-
require adapter_schema if File.
|
36
|
-
|
37
|
-
Dir[File.dirname(__FILE__) + "/models/*.rb"].each{ |file| require file }
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
table_types =
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
puts
|
68
|
-
puts "Done with benchmark!"
|
1
|
+
require 'pathname'
|
2
|
+
require "fileutils"
|
3
|
+
require "active_record"
|
4
|
+
|
5
|
+
benchmark_dir = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift('.')
|
8
|
+
|
9
|
+
# Get the gem into the load path
|
10
|
+
$LOAD_PATH.unshift(File.join(benchmark_dir, '..', 'lib'))
|
11
|
+
|
12
|
+
# Load the benchmark files
|
13
|
+
Dir[File.join( benchmark_dir, 'lib', '*.rb' )].sort.each { |f| require f }
|
14
|
+
|
15
|
+
# Parse the options passed in via the command line
|
16
|
+
options = BenchmarkOptionParser.parse( ARGV )
|
17
|
+
|
18
|
+
FileUtils.mkdir_p 'log'
|
19
|
+
ActiveRecord::Base.configurations["test"] = YAML.load_file(File.join(benchmark_dir, "../test/database.yml"))[options.adapter]
|
20
|
+
ActiveRecord::Base.logger = Logger.new("log/test.log")
|
21
|
+
ActiveRecord::Base.logger.level = Logger::DEBUG
|
22
|
+
ActiveRecord::Base.default_timezone = :utc
|
23
|
+
|
24
|
+
require "activerecord-import"
|
25
|
+
ActiveRecord::Base.establish_connection(:test)
|
26
|
+
|
27
|
+
ActiveSupport::Notifications.subscribe(/active_record.sql/) do |_, _, _, _, hsh|
|
28
|
+
ActiveRecord::Base.logger.info hsh[:sql]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Load base/generic schema
|
32
|
+
require File.join(benchmark_dir, "../test/schema/version")
|
33
|
+
require File.join(benchmark_dir, "../test/schema/generic_schema")
|
34
|
+
adapter_schema = File.join(benchmark_dir, "schema/#{options.adapter}_schema.rb")
|
35
|
+
require adapter_schema if File.exist?(adapter_schema)
|
36
|
+
|
37
|
+
Dir[File.dirname(__FILE__) + "/models/*.rb"].each { |file| require file }
|
38
|
+
|
39
|
+
require File.join( benchmark_dir, 'lib', "#{options.adapter}_benchmark" )
|
40
|
+
|
41
|
+
table_types = nil
|
42
|
+
table_types = if options.benchmark_all_types
|
43
|
+
["all"]
|
44
|
+
else
|
45
|
+
options.table_types.keys
|
46
|
+
end
|
47
|
+
|
48
|
+
letter = options.adapter[0].chr
|
49
|
+
clazz_str = letter.upcase + options.adapter[1..-1].downcase
|
50
|
+
clazz = Object.const_get( clazz_str + "Benchmark" )
|
51
|
+
|
52
|
+
benchmarks = []
|
53
|
+
options.number_of_objects.each do |num|
|
54
|
+
benchmarks << (benchmark = clazz.new)
|
55
|
+
benchmark.send( "benchmark", table_types, num )
|
56
|
+
end
|
57
|
+
|
58
|
+
options.outputs.each do |output|
|
59
|
+
format = output.format.downcase
|
60
|
+
output_module = Object.const_get( "OutputTo#{format.upcase}" )
|
61
|
+
benchmarks.each do |benchmark|
|
62
|
+
output_module.output_results( output.filename, benchmark.results )
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
puts
|
67
|
+
puts "Done with benchmark!"
|
data/benchmarks/lib/base.rb
CHANGED
@@ -1,137 +1,136 @@
|
|
1
|
-
class BenchmarkBase
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# *
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# *
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# *
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
# *
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
puts
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
description = "#{model_clazz.name}.import(column, values) for #{num_inserts} records with validations"
|
67
|
-
group << bm( description ) { model_clazz.import cols, vals, :
|
68
|
-
|
69
|
-
description = "#{model_clazz.name}.import(columns, values) for #{num_inserts} records without validations"
|
70
|
-
group << bm( description ) { model_clazz.import cols, vals, :
|
71
|
-
|
72
|
-
models = []
|
73
|
-
array_of_attrs = []
|
74
|
-
|
75
|
-
vals.each do |arr|
|
76
|
-
array_of_attrs << (attrs={})
|
77
|
-
arr.each_with_index { |value, i| attrs[cols[i]] = value }
|
78
|
-
end
|
79
|
-
array_of_attrs.each{ |attrs| models << model_clazz.new(attrs) }
|
80
|
-
|
81
|
-
description = "#{model_clazz.name}.import(models) for #{num_inserts} records with validations"
|
82
|
-
group << bm( description ) { model_clazz.import models, :
|
83
|
-
|
84
|
-
description = "#{model_clazz.name}.import(models) for #{num_inserts} records without validations"
|
85
|
-
group << bm( description ) { model_clazz.import models, :
|
86
|
-
|
87
|
-
true
|
88
|
-
end
|
89
|
-
|
90
|
-
# Returns a two element array composing of an array of columns and an array of
|
91
|
-
# value sets given the passed +num+.
|
92
|
-
#
|
93
|
-
# === What is a value set?
|
94
|
-
# A value set is an array of arrays. Each child array represents an array of value sets
|
95
|
-
# for a given row of data.
|
96
|
-
#
|
97
|
-
# For example, say we wanted to represent an insertion of two records:
|
98
|
-
# column_names = [ 'id', 'name', 'description' ]
|
99
|
-
# record1 = [ 1, 'John Doe', 'A plumber' ]
|
100
|
-
# record2 = [ 2, 'John Smith', 'A painter' ]
|
101
|
-
# value_set [ record1, record2 ]
|
102
|
-
#
|
103
|
-
# == PARAMETER
|
104
|
-
# * num - the number of records to create
|
105
|
-
def build_array_of_cols_and_vals( num )
|
106
|
-
cols = [
|
107
|
-
value_sets = []
|
108
|
-
num.times { |i| value_sets << [
|
109
|
-
[
|
110
|
-
end
|
111
|
-
|
112
|
-
# Returns a hash of column identifier to value mappings giving the passed in
|
113
|
-
# value array.
|
114
|
-
#
|
115
|
-
# Example:
|
116
|
-
# cols = [ 'id', 'name', 'description' ]
|
117
|
-
# values = [ 1, 'John Doe', 'A plumber' ]
|
118
|
-
# hsh = create_hash_for_cols_and_vals( cols, values )
|
119
|
-
# # hsh => { 'id'=>1, 'name'=>'John Doe', 'description'=>'A plumber' }
|
120
|
-
def create_hash_for_cols_and_vals( cols, vals )
|
121
|
-
h = {}
|
122
|
-
cols.zip( vals ){ |col,val| h[col] = val }
|
123
|
-
h
|
124
|
-
end
|
125
|
-
|
126
|
-
# Deletes all records from all ActiveRecord subclasses
|
127
|
-
def delete_all
|
128
|
-
ActiveRecord::Base.send( :subclasses ).each do |subclass|
|
129
|
-
subclass.delete_all if subclass.respond_to? :delete_all
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def initialize
|
134
|
-
@results = []
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
1
|
+
class BenchmarkBase
|
2
|
+
attr_reader :results
|
3
|
+
|
4
|
+
# The main benchmark method dispatcher. This dispatches the benchmarks
|
5
|
+
# to actual benchmark_xxxx methods.
|
6
|
+
#
|
7
|
+
# == PARAMETERS
|
8
|
+
# * table_types - an array of table types to benchmark
|
9
|
+
# * num - the number of record insertions to test
|
10
|
+
def benchmark( table_types, num )
|
11
|
+
array_of_cols_and_vals = build_array_of_cols_and_vals( num )
|
12
|
+
table_types.each do |table_type|
|
13
|
+
send( "benchmark_#{table_type}", array_of_cols_and_vals )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns an OpenStruct which contains two attritues, +description+ and +tms+ after performing an
|
18
|
+
# actual benchmark.
|
19
|
+
#
|
20
|
+
# == PARAMETERS
|
21
|
+
# * description - the description of the block that is getting benchmarked
|
22
|
+
# * blk - the block of code to benchmark
|
23
|
+
#
|
24
|
+
# == RETURNS
|
25
|
+
# An OpenStruct object with the following attributes:
|
26
|
+
# * description - the description of the benchmark ran
|
27
|
+
# * tms - a Benchmark::Tms containing the results of the benchmark
|
28
|
+
def bm( description )
|
29
|
+
tms = nil
|
30
|
+
puts "Benchmarking #{description}"
|
31
|
+
|
32
|
+
Benchmark.bm { |x| tms = x.report { yield } }
|
33
|
+
delete_all
|
34
|
+
failed = false
|
35
|
+
|
36
|
+
OpenStruct.new description: description, tms: tms, failed: failed
|
37
|
+
end
|
38
|
+
|
39
|
+
# Given a model class (ie: Topic), and an array of columns and value sets
|
40
|
+
# this will perform all of the benchmarks necessary for this library.
|
41
|
+
#
|
42
|
+
# == PARAMETERS
|
43
|
+
# * model_clazz - the model class to benchmark (ie: Topic)
|
44
|
+
# * array_of_cols_and_vals - an array of column identifiers and value sets
|
45
|
+
#
|
46
|
+
# == RETURNS
|
47
|
+
# returns true
|
48
|
+
def bm_model( model_clazz, array_of_cols_and_vals )
|
49
|
+
puts
|
50
|
+
puts "------ Benchmarking #{model_clazz.name} -------"
|
51
|
+
|
52
|
+
cols, vals = array_of_cols_and_vals
|
53
|
+
num_inserts = vals.size
|
54
|
+
|
55
|
+
# add a new result group for this particular benchmark
|
56
|
+
group = []
|
57
|
+
@results << group
|
58
|
+
|
59
|
+
description = "#{model_clazz.name}.create (#{num_inserts} records)"
|
60
|
+
group << bm( description ) do
|
61
|
+
vals.each do |values|
|
62
|
+
model_clazz.create create_hash_for_cols_and_vals( cols, values )
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
description = "#{model_clazz.name}.import(column, values) for #{num_inserts} records with validations"
|
67
|
+
group << bm( description ) { model_clazz.import cols, vals, validate: true }
|
68
|
+
|
69
|
+
description = "#{model_clazz.name}.import(columns, values) for #{num_inserts} records without validations"
|
70
|
+
group << bm( description ) { model_clazz.import cols, vals, validate: false }
|
71
|
+
|
72
|
+
models = []
|
73
|
+
array_of_attrs = []
|
74
|
+
|
75
|
+
vals.each do |arr|
|
76
|
+
array_of_attrs << (attrs = {})
|
77
|
+
arr.each_with_index { |value, i| attrs[cols[i]] = value }
|
78
|
+
end
|
79
|
+
array_of_attrs.each { |attrs| models << model_clazz.new(attrs) }
|
80
|
+
|
81
|
+
description = "#{model_clazz.name}.import(models) for #{num_inserts} records with validations"
|
82
|
+
group << bm( description ) { model_clazz.import models, validate: true }
|
83
|
+
|
84
|
+
description = "#{model_clazz.name}.import(models) for #{num_inserts} records without validations"
|
85
|
+
group << bm( description ) { model_clazz.import models, validate: false }
|
86
|
+
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns a two element array composing of an array of columns and an array of
|
91
|
+
# value sets given the passed +num+.
|
92
|
+
#
|
93
|
+
# === What is a value set?
|
94
|
+
# A value set is an array of arrays. Each child array represents an array of value sets
|
95
|
+
# for a given row of data.
|
96
|
+
#
|
97
|
+
# For example, say we wanted to represent an insertion of two records:
|
98
|
+
# column_names = [ 'id', 'name', 'description' ]
|
99
|
+
# record1 = [ 1, 'John Doe', 'A plumber' ]
|
100
|
+
# record2 = [ 2, 'John Smith', 'A painter' ]
|
101
|
+
# value_set [ record1, record2 ]
|
102
|
+
#
|
103
|
+
# == PARAMETER
|
104
|
+
# * num - the number of records to create
|
105
|
+
def build_array_of_cols_and_vals( num )
|
106
|
+
cols = [:my_name, :description]
|
107
|
+
value_sets = []
|
108
|
+
num.times { |i| value_sets << ["My Name #{i}", "My Description #{i}"] }
|
109
|
+
[cols, value_sets]
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns a hash of column identifier to value mappings giving the passed in
|
113
|
+
# value array.
|
114
|
+
#
|
115
|
+
# Example:
|
116
|
+
# cols = [ 'id', 'name', 'description' ]
|
117
|
+
# values = [ 1, 'John Doe', 'A plumber' ]
|
118
|
+
# hsh = create_hash_for_cols_and_vals( cols, values )
|
119
|
+
# # hsh => { 'id'=>1, 'name'=>'John Doe', 'description'=>'A plumber' }
|
120
|
+
def create_hash_for_cols_and_vals( cols, vals )
|
121
|
+
h = {}
|
122
|
+
cols.zip( vals ) { |col, val| h[col] = val }
|
123
|
+
h
|
124
|
+
end
|
125
|
+
|
126
|
+
# Deletes all records from all ActiveRecord subclasses
|
127
|
+
def delete_all
|
128
|
+
ActiveRecord::Base.send( :subclasses ).each do |subclass|
|
129
|
+
subclass.delete_all if subclass.respond_to? :delete_all
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def initialize # :nodoc:
|
134
|
+
@results = []
|
135
|
+
end
|
136
|
+
end
|