active_record_bulk_insert 1.0.1 → 1.0.2
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/README.md +17 -0
- data/lib/active_record_bulk_insert.rb +10 -12
- data/spec/sample_record_spec.rb +111 -85
- data/spec/support/migrations/1_sample_record_migration.rb +1 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3d14d962a4b75438e6782bcfb7ae0d25c9f1bd5
|
4
|
+
data.tar.gz: f8878c7b4b47eb1f5daaff16135ceb03b491830b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a0fdf6b3acad9e058d3bea8c2cc304edd6fab80d278a7ade049debd93cade9283138cd00a91cb05429c25de179cb4825c5e20915c14f2bab3796238fa732a84
|
7
|
+
data.tar.gz: 417f5e0f23e63e5d7ee3e51af9aaa25c942a95185b30ef57869e663a32a49b90deb270f2b2379e076511e80b3ac919cedde31219de610e3ed9b8df30cffdd8f3
|
data/README.md
CHANGED
@@ -6,6 +6,15 @@
|
|
6
6
|
|
7
7
|
### Quick Example
|
8
8
|
|
9
|
+
For -v 1.0.0
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
#Gemfile
|
13
|
+
gem "active_record_bulk_insert", :require => 'base'
|
14
|
+
```
|
15
|
+
|
16
|
+
For subsequent versions
|
17
|
+
|
9
18
|
```ruby
|
10
19
|
#Gemfile
|
11
20
|
gem "active_record_bulk_insert"
|
@@ -50,6 +59,14 @@ User.bulk_insert(users, :use_provided_primary_key => true)
|
|
50
59
|
```
|
51
60
|
*note this is only available from ActiveRecord 4.0 as id was protected from mass-assignment in ActiveRecord < 4.0*
|
52
61
|
|
62
|
+
### Disable default timestamps
|
63
|
+
|
64
|
+
*From version 1.0.2 updated_at and created_at are provided by default*
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
User.bulk_insert(users, :disable_timestamps => true)
|
68
|
+
```
|
69
|
+
|
53
70
|
### Bulk insert in batches
|
54
71
|
|
55
72
|
```ruby
|
@@ -8,15 +8,17 @@ ActiveRecord::Base.class_eval do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.bulk_insert(attrs, options = {})
|
11
|
+
return [] if attrs.empty?
|
12
|
+
|
11
13
|
use_provided_primary_key = options.fetch(:use_provided_primary_key, false)
|
12
|
-
attributes = _resolve_record(attrs.first,
|
14
|
+
attributes = _resolve_record(attrs.first, options).keys.join(", ")
|
13
15
|
|
14
16
|
if options.fetch(:validate, false)
|
15
17
|
attrs, invalid = attrs.partition { |record| _validate(record) }
|
16
18
|
end
|
17
19
|
|
18
20
|
values_sql = attrs.map do |record|
|
19
|
-
"(#{_resolve_record(record,
|
21
|
+
"(#{_resolve_record(record, options).values.map { |r| sanitize(r) }.join(', ')})"
|
20
22
|
end.join(",")
|
21
23
|
|
22
24
|
sql = <<-SQL
|
@@ -29,16 +31,12 @@ ActiveRecord::Base.class_eval do
|
|
29
31
|
invalid
|
30
32
|
end
|
31
33
|
|
32
|
-
def self._resolve_record(record,
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
record.attributes
|
39
|
-
elsif record.is_a?(ActiveRecord::Base)
|
40
|
-
record.attributes.except(primary_key).except(primary_key.to_sym)
|
41
|
-
end
|
34
|
+
def self._resolve_record(record, options)
|
35
|
+
time = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
|
36
|
+
_record = record.is_a?(ActiveRecord::Base) ? record.attributes : record
|
37
|
+
_record.merge!("created_at" => time, "updated_at" => time) unless options.fetch(:disable_timestamps, false)
|
38
|
+
_record = _record.except(primary_key).except(primary_key.to_sym) unless options.fetch(:use_provided_primary_key, false)
|
39
|
+
_record
|
42
40
|
end
|
43
41
|
|
44
42
|
def self._validate(record)
|
data/spec/sample_record_spec.rb
CHANGED
@@ -1,89 +1,115 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe SampleRecord do
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
4
|
+
describe "bulk_insert" do
|
5
|
+
it "inserts records into the DB" do
|
6
|
+
ActiveRecord::ConnectionAdapters::SQLite3Adapter.any_instance.should_receive(:execute).with do |params|
|
7
|
+
params.should include("INSERT INTO \"sample_records\"")
|
8
|
+
params.should include("Foo")
|
9
|
+
params.should include("30")
|
10
|
+
end.once
|
11
|
+
SampleRecord.bulk_insert([{:name => "Foo", :age => 30}])
|
12
|
+
end
|
13
|
+
|
14
|
+
it "inserts records into the DB and increases count of records" do
|
15
|
+
records = 5.times.map { |i| SampleRecord.new(:age => i + (30..50).to_a.sample, :name => "Foo#{i}").attributes }
|
16
|
+
expect {SampleRecord.bulk_insert(records)}.to change{SampleRecord.count}.by(records.size)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "inserts multiple records into the DB in a single insert statement" do
|
20
|
+
records = 10.times.map { |i| {:age => 4, :name => "Foo#{i}"} }
|
21
|
+
|
22
|
+
ActiveRecord::ConnectionAdapters::SQLite3Adapter.any_instance.should_receive(:execute).with do |params|
|
23
|
+
matchdata = params.match(/insert into "sample_records"/i)
|
24
|
+
matchdata.to_a.count.should == 1
|
25
|
+
records.each do |record|
|
26
|
+
params.should include(record[:age].to_s)
|
27
|
+
params.should include(record[:name])
|
28
|
+
end
|
29
|
+
end.once
|
30
|
+
|
31
|
+
SampleRecord.bulk_insert(records)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "relies on the DB to provide primary_key if :use_provided_primary_key is false or nil" do
|
35
|
+
records = 10.times.map { |i| SampleRecord.new(:id => 10000 + i, :age => 4, :name => "Foo#{i}") }
|
36
|
+
|
37
|
+
ActiveRecord::ConnectionAdapters::SQLite3Adapter.any_instance.should_receive(:execute).with do |params|
|
38
|
+
records.each do |record|
|
39
|
+
params.should_not include(record.id.to_s)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
SampleRecord.bulk_insert(records)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "uses provided primary_key if :use_provided_primary_key is true" do
|
47
|
+
records = 10.times.map { |i| SampleRecord.new(:id => 10000 + i, :age => 4, :name => "Foo#{i}") }
|
48
|
+
|
49
|
+
SampleRecord.bulk_insert(records, :use_provided_primary_key => true)
|
50
|
+
records.each do |record|
|
51
|
+
SampleRecord.exists?(:id => record.id).should be_true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "support insertion of ActiveRecord objects" do
|
56
|
+
records = 10.times.map { |i| SampleRecord.new(:age => 4, :name => "Foo#{i}") }
|
57
|
+
|
58
|
+
ActiveRecord::ConnectionAdapters::SQLite3Adapter.any_instance.should_receive(:execute).with do |params|
|
59
|
+
matchdata = params.match(/insert into "sample_records"/i)
|
60
|
+
matchdata.to_a.count.should == 1
|
61
|
+
records.each do |record|
|
62
|
+
params.should include(record.age.to_s)
|
63
|
+
params.should include(record.name)
|
64
|
+
end
|
65
|
+
end.once
|
66
|
+
|
67
|
+
SampleRecord.bulk_insert(records)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "doesn't blow up on an empty array" do
|
71
|
+
expect do
|
72
|
+
SampleRecord.bulk_insert([])
|
73
|
+
end.to_not raise_error
|
74
|
+
end
|
75
|
+
|
76
|
+
context "validations" do
|
77
|
+
it "should not persist invalid records if ':validate => true' is specified" do
|
78
|
+
SampleRecord.send(:validates, :name, :presence => true)
|
79
|
+
expect {SampleRecord.bulk_insert([:age => 30], :validate => true)}.to_not change{SampleRecord.count}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "timestamps" do
|
84
|
+
it "sets created_at and updated_at by default" do
|
85
|
+
records = 10.times.map { |i| SampleRecord.new(:id => 10000 + i, :age => 4, :name => "Foo#{i}") }
|
86
|
+
SampleRecord.bulk_insert(records)
|
87
|
+
|
88
|
+
SampleRecord.all.each do |record|
|
89
|
+
record.created_at.should_not be_nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "does not set created_at and updated_at if :disable_timestamps is true" do
|
94
|
+
records = 10.times.map { |i| SampleRecord.new(:id => 10000 + i, :age => 4, :name => "Foo#{i}") }
|
95
|
+
SampleRecord.bulk_insert(records, :disable_timestamps => true)
|
96
|
+
|
97
|
+
SampleRecord.all.each do |record|
|
98
|
+
record.created_at.should be_nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "bulk_insert_in_batches" do
|
105
|
+
it "allows you to specify a batch_size" do
|
106
|
+
records = 10.times.map { |i| SampleRecord.new(:age => 4, :name => "Foo#{i}").attributes }
|
107
|
+
|
108
|
+
ActiveRecord::ConnectionAdapters::SQLite3Adapter.any_instance.should_receive(:execute).with do |params|
|
109
|
+
params.should include("INSERT INTO \"sample_records\"")
|
110
|
+
end.exactly(5).times
|
111
|
+
|
112
|
+
SampleRecord.bulk_insert_in_batches(records, :batch_size => 2)
|
113
|
+
end
|
114
|
+
end
|
89
115
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_bulk_insert
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abejide Ayodele
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05
|
11
|
+
date: 2014-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -104,7 +104,7 @@ signing_key:
|
|
104
104
|
specification_version: 4
|
105
105
|
summary: bulk insert records into the DB
|
106
106
|
test_files:
|
107
|
+
- spec/support/sample_record.rb
|
108
|
+
- spec/support/migrations/1_sample_record_migration.rb
|
107
109
|
- spec/sample_record_spec.rb
|
108
110
|
- spec/spec_helper.rb
|
109
|
-
- spec/support/migrations/1_sample_record_migration.rb
|
110
|
-
- spec/support/sample_record.rb
|