activerecord-import 0.12.0 → 0.13.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 +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
|