bulk_data_methods 1.0.0 → 1.1.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.
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/LICENSE +1 -1
- data/README.md +91 -0
- data/Rakefile +10 -1
- data/bulk_data_methods.gemspec +2 -2
- data/lib/bulk_data_methods/bulk_methods_mixin.rb +29 -11
- data/lib/bulk_data_methods/version.rb +1 -1
- data/spec/bulk_data_methods/bulk_methods_mixin_spec.rb +7 -4
- metadata +5 -5
- data/Gemfile.lock +0 -108
- data/README +0 -68
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
+
# NOTE(ahannon) Travis CI kindly requests that the debugger be split
|
4
|
+
# out so that it does not install linecache during "bundle install":
|
5
|
+
group :debug do
|
6
|
+
gem 'debugger'
|
7
|
+
end
|
8
|
+
|
3
9
|
# Specify your gem's dependencies in bulk_data_methods.gemspec
|
4
10
|
gemspec
|
data/LICENSE
CHANGED
data/README.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
bulk_data_methods
|
2
|
+
==================
|
3
|
+
MixIn used to extend ActiveRecord::Base classes implementing bulk insert and update operations
|
4
|
+
through {#create_many} and {#update_many}.
|
5
|
+
|
6
|
+
Examples
|
7
|
+
========
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class Company < ActiveRecord::Base
|
11
|
+
extend BulkMethodsMixin
|
12
|
+
end
|
13
|
+
```
|
14
|
+
__________________________
|
15
|
+
BULK creation of many rows:
|
16
|
+
|
17
|
+
example no options used
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
rows = [
|
21
|
+
{ :name => 'Keith', :salary => 1000 },
|
22
|
+
{ :name => 'Alex', :salary => 2000 }
|
23
|
+
]
|
24
|
+
Employee.create_many(rows)
|
25
|
+
```
|
26
|
+
|
27
|
+
example with :returning option to returns key value
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
rows = [
|
31
|
+
{ :name => 'Keith', :salary => 1000 },
|
32
|
+
{ :name => 'Alex', :salary => 2000 }
|
33
|
+
]
|
34
|
+
options = { :returning => [:id] }
|
35
|
+
Employee.create_many(rows, options)
|
36
|
+
```
|
37
|
+
|
38
|
+
example with :slice_size option (will generate two insert queries)
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
rows = [
|
42
|
+
{ :name => 'Keith', :salary => 1000 },
|
43
|
+
{ :name => 'Alex', :salary => 2000 },
|
44
|
+
{ :name => 'Mark', :salary => 3000 }
|
45
|
+
]
|
46
|
+
options = { :slice_size => 2 }
|
47
|
+
Employee.create_many(rows, options)
|
48
|
+
```
|
49
|
+
|
50
|
+
_________________________
|
51
|
+
BULK updates of many rows:
|
52
|
+
|
53
|
+
example using "set_array" to add the value of "salary" to the specific
|
54
|
+
employee's salary the default where clause matches IDs so, it works
|
55
|
+
here.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
rows = [
|
59
|
+
{ :id => 1, :salary => 1000 },
|
60
|
+
{ :id => 10, :salary => 2000 },
|
61
|
+
{ :id => 23, :salary => 2500 }
|
62
|
+
]
|
63
|
+
options = { :set_array => '"salary = datatable.salary"' }
|
64
|
+
Employee.update_many(rows, options)
|
65
|
+
```
|
66
|
+
|
67
|
+
example using where clause to only update salaries that haven't already been updated (forced exampled).
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
rows = [
|
71
|
+
{ :id => 1, :salary => 1000, :company_id => 10 },
|
72
|
+
{ :id => 10, :salary => 2000, :company_id => 12 },
|
73
|
+
{ :id => 23, :salary => 2500, :company_id => 5 }
|
74
|
+
]
|
75
|
+
options = {
|
76
|
+
:set_array => '"salary = datatable.salary"',
|
77
|
+
:where_datatable => '"#{table_name}.salary <> datatable.salary"'
|
78
|
+
}
|
79
|
+
Employee.update_many(rows, options)
|
80
|
+
```
|
81
|
+
|
82
|
+
example setting where clause to the KEY of the hash passed in and the set_array is generated from the VALUES
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
rows = {
|
86
|
+
{ :id => 1 } => { :salary => 100000, :company_id => 10 },
|
87
|
+
{ :id => 10 } => { :salary => 110000, :company_id => 12 },
|
88
|
+
{ :id => 23 } => { :salary => 90000, :company_id => 5 }
|
89
|
+
}
|
90
|
+
Employee.update_many(rows)
|
91
|
+
```
|
data/Rakefile
CHANGED
@@ -1 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
require 'rspec/core'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
6
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
7
|
+
spec.ruby_opts="-w"
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default => :spec
|
data/bulk_data_methods.gemspec
CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
|
|
5
5
|
s.name = "bulk_data_methods"
|
6
6
|
s.version = BulkDataMethods::VERSION
|
7
7
|
s.license = 'New BSD License'
|
8
|
-
s.date = '
|
8
|
+
s.date = '2013-05-30'
|
9
9
|
s.summary = 'MixIn used to extend ActiveRecord::Base classes implementing bulk insert and update operations through {#create_many} and {#update_many}.'
|
10
10
|
s.description = 'MixIn used to extend ActiveRecord::Base classes implementing bulk insert and update operations through {#create_many} and {#update_many}.'
|
11
11
|
s.authors = ["Keith Gabryelski"]
|
@@ -17,4 +17,4 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.add_dependency "pg"
|
18
18
|
s.add_dependency "rails", '>= 3.0.0'
|
19
19
|
s.add_dependency 'rspec-rails'
|
20
|
-
end
|
20
|
+
end
|
@@ -113,12 +113,14 @@ module BulkMethodsMixin
|
|
113
113
|
# @overload update_many(rows = [], options = {})
|
114
114
|
# @param [Array<Hash>] rows ([]) data to be updated
|
115
115
|
# @option options [String] :set_array (built from first row passed in) the set clause
|
116
|
-
# @option options [String] :
|
116
|
+
# @option options [String] :where_datatable ('"#{table_name}.id = datatable.id"') the where clause specifying how to join the datatable against the real table
|
117
|
+
# @option options [String] :where_constraint the rest of the where clause that limits what rows of the table get updated
|
117
118
|
#
|
118
119
|
# @overload update_many(rows = {}, options = {})
|
119
120
|
# @param [Hash<Hash, Hash>] rows ({}) data to be updated
|
120
121
|
# @option options [String] :set_array (built from the values in the first key/value pair of `rows`) the set clause
|
121
|
-
# @option options [String] :
|
122
|
+
# @option options [String] :where_datatable ('"#{table_name}.id = datatable.id"') the where clause specifying how to join the datatable against the real table
|
123
|
+
# @option options [String] :where_constraint the rest of the where clause that limits what rows of the table get updated
|
122
124
|
#
|
123
125
|
# @example using "set_array" to add the value of "salary" to the specific employee's salary the default where clause matches IDs so, it works here.
|
124
126
|
# rows = [
|
@@ -129,15 +131,27 @@ module BulkMethodsMixin
|
|
129
131
|
# options = { :set_array => '"salary = datatable.salary"' }
|
130
132
|
# Employee.update_many(rows, options)
|
131
133
|
#
|
132
|
-
# @example using
|
134
|
+
# @example using where_datatable clause to match salary.
|
133
135
|
# rows = [
|
134
136
|
# { :id => 1, :salary => 1000, :company_id => 10 },
|
135
137
|
# { :id => 10, :salary => 2000, :company_id => 12 },
|
136
138
|
# { :id => 23, :salary => 2500, :company_id => 5 }
|
137
139
|
# ]
|
138
140
|
# options = {
|
139
|
-
# :set_array => '"
|
140
|
-
# :
|
141
|
+
# :set_array => '"salary = datatable.salary"',
|
142
|
+
# :where_constraint => '"#{table_name}.salary <> datatable.salary"'
|
143
|
+
# }
|
144
|
+
# Employee.update_many(rows, options)
|
145
|
+
#
|
146
|
+
# @example using where_constraint clause to only update salary for active employees
|
147
|
+
# rows = [
|
148
|
+
# { :id => 1, :salary => 1000, :company_id => 10 },
|
149
|
+
# { :id => 10, :salary => 2000, :company_id => 12 },
|
150
|
+
# { :id => 23, :salary => 2500, :company_id => 5 }
|
151
|
+
# ]
|
152
|
+
# options = {
|
153
|
+
# :set_array => '"salary = datatable.salary"',
|
154
|
+
# :where_constraint => '"#{table_name}.active = true"'
|
141
155
|
# }
|
142
156
|
# Employee.update_many(rows, options)
|
143
157
|
#
|
@@ -155,7 +169,7 @@ module BulkMethodsMixin
|
|
155
169
|
def update_many(rows, options = {})
|
156
170
|
return [] if rows.blank?
|
157
171
|
if rows.is_a?(Hash)
|
158
|
-
options[:
|
172
|
+
options[:where_datatable] = '"' + rows.keys[0].keys.map{|key| '#{table_name}.' + "#{key} = datatable.#{key}"}.join(' and ') + '"'
|
159
173
|
options[:set_array] = '"' + rows.values[0].keys.map{|key| "#{key} = datatable.#{key}"}.join(',') + '"' unless options[:set_array]
|
160
174
|
r = []
|
161
175
|
rows.each do |key,value|
|
@@ -166,8 +180,8 @@ module BulkMethodsMixin
|
|
166
180
|
unless options[:set_array]
|
167
181
|
column_names = rows[0].keys
|
168
182
|
columns_to_remove = [:id]
|
169
|
-
columns_to_remove +=
|
170
|
-
options[:set_array] = '"' + (column_names - columns_to_remove
|
183
|
+
columns_to_remove += partition_keys.flatten.map{|k| k.to_sym} if respond_to?(:partition_keys)
|
184
|
+
options[:set_array] = '"' + (column_names - columns_to_remove).map{|cn| "#{cn} = datatable.#{cn}"}.join(',') + '"'
|
171
185
|
end
|
172
186
|
options[:slice_size] = 1000 unless options[:slice_size]
|
173
187
|
options[:check_consistency] = true unless options.has_key?(:check_consistency)
|
@@ -180,8 +194,11 @@ module BulkMethodsMixin
|
|
180
194
|
end
|
181
195
|
returning_clause = "\" returning #{returning_list}\""
|
182
196
|
end
|
183
|
-
options[:
|
184
|
-
|
197
|
+
where_clause = options[:where_datatable] || '"#{table_name}.id = datatable.id"'
|
198
|
+
where_constraint = ""
|
199
|
+
if options[:where_constraint]
|
200
|
+
where_constraint = " AND #{eval(options[:where_constraint])}"
|
201
|
+
end
|
185
202
|
returning = []
|
186
203
|
|
187
204
|
rows.group_by do |row|
|
@@ -217,7 +234,8 @@ module BulkMethodsMixin
|
|
217
234
|
#{datatable}
|
218
235
|
) as datatable
|
219
236
|
where
|
220
|
-
#{eval(
|
237
|
+
#{eval(where_clause)}
|
238
|
+
#{where_constraint}
|
221
239
|
#{eval(returning_clause)}
|
222
240
|
SQL
|
223
241
|
returning += find_by_sql(sql_update_string)
|
@@ -346,15 +346,18 @@ describe "BulkMethodsMixin" do
|
|
346
346
|
end
|
347
347
|
end # when update method with options :set_array equal 'salary = datatable.salary'
|
348
348
|
|
349
|
-
context "when update method with options :
|
349
|
+
context "when update method with options :where_constraint" do
|
350
350
|
it "updates only name column, where salary equal input values" do
|
351
351
|
Employee.update_many([{ :id => 1, :name => 'Elvis', :salary => 12 },
|
352
|
-
{ :id => 2, :name => 'Freddi',:salary => 22}
|
353
|
-
{ :
|
352
|
+
{ :id => 2, :name => 'Freddi',:salary => 22},
|
353
|
+
{ :id => 3, :name => 'Robert', :salary => 13}],
|
354
|
+
{ :where_constraint => '"#{table_name}.salary = datatable.salary AND datatable.salary < 13"' })
|
354
355
|
Employee.find(1).name.should_not == "Elvis"
|
355
356
|
Employee.find(1).salary.should == 3
|
356
357
|
Employee.find(2).name.should_not == "Freddi"
|
357
358
|
Employee.find(2).salary.should == 3
|
359
|
+
Employee.find(3).name.should_not == "Robert"
|
360
|
+
Employee.find(3).salary.should == 3
|
358
361
|
end
|
359
362
|
end # when update method with options :where
|
360
363
|
|
@@ -433,4 +436,4 @@ describe "BulkMethodsMixin" do
|
|
433
436
|
|
434
437
|
end # update_many
|
435
438
|
|
436
|
-
end # BulkMethodsMixin
|
439
|
+
end # BulkMethodsMixin
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bulk_data_methods
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-05-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pg
|
@@ -68,10 +68,10 @@ extra_rdoc_files: []
|
|
68
68
|
files:
|
69
69
|
- .gitignore
|
70
70
|
- .rspec
|
71
|
+
- .travis.yml
|
71
72
|
- Gemfile
|
72
|
-
- Gemfile.lock
|
73
73
|
- LICENSE
|
74
|
-
- README
|
74
|
+
- README.md
|
75
75
|
- Rakefile
|
76
76
|
- bulk_data_methods.gemspec
|
77
77
|
- lib/bulk_data_methods.rb
|
@@ -132,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
132
|
version: '0'
|
133
133
|
requirements: []
|
134
134
|
rubyforge_project:
|
135
|
-
rubygems_version: 1.8.
|
135
|
+
rubygems_version: 1.8.25
|
136
136
|
signing_key:
|
137
137
|
specification_version: 3
|
138
138
|
summary: MixIn used to extend ActiveRecord::Base classes implementing bulk insert
|
data/Gemfile.lock
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
bulk_data_methods (1.0.0)
|
5
|
-
pg
|
6
|
-
rails (>= 3.0.0)
|
7
|
-
rspec-rails
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: https://rubygems.org/
|
11
|
-
specs:
|
12
|
-
actionmailer (3.2.8)
|
13
|
-
actionpack (= 3.2.8)
|
14
|
-
mail (~> 2.4.4)
|
15
|
-
actionpack (3.2.8)
|
16
|
-
activemodel (= 3.2.8)
|
17
|
-
activesupport (= 3.2.8)
|
18
|
-
builder (~> 3.0.0)
|
19
|
-
erubis (~> 2.7.0)
|
20
|
-
journey (~> 1.0.4)
|
21
|
-
rack (~> 1.4.0)
|
22
|
-
rack-cache (~> 1.2)
|
23
|
-
rack-test (~> 0.6.1)
|
24
|
-
sprockets (~> 2.1.3)
|
25
|
-
activemodel (3.2.8)
|
26
|
-
activesupport (= 3.2.8)
|
27
|
-
builder (~> 3.0.0)
|
28
|
-
activerecord (3.2.8)
|
29
|
-
activemodel (= 3.2.8)
|
30
|
-
activesupport (= 3.2.8)
|
31
|
-
arel (~> 3.0.2)
|
32
|
-
tzinfo (~> 0.3.29)
|
33
|
-
activeresource (3.2.8)
|
34
|
-
activemodel (= 3.2.8)
|
35
|
-
activesupport (= 3.2.8)
|
36
|
-
activesupport (3.2.8)
|
37
|
-
i18n (~> 0.6)
|
38
|
-
multi_json (~> 1.0)
|
39
|
-
arel (3.0.2)
|
40
|
-
builder (3.0.3)
|
41
|
-
diff-lcs (1.1.3)
|
42
|
-
erubis (2.7.0)
|
43
|
-
hike (1.2.1)
|
44
|
-
i18n (0.6.1)
|
45
|
-
journey (1.0.4)
|
46
|
-
json (1.7.5)
|
47
|
-
mail (2.4.4)
|
48
|
-
i18n (>= 0.4.0)
|
49
|
-
mime-types (~> 1.16)
|
50
|
-
treetop (~> 1.4.8)
|
51
|
-
mime-types (1.19)
|
52
|
-
multi_json (1.3.6)
|
53
|
-
pg (0.14.1)
|
54
|
-
polyglot (0.3.3)
|
55
|
-
rack (1.4.1)
|
56
|
-
rack-cache (1.2)
|
57
|
-
rack (>= 0.4)
|
58
|
-
rack-ssl (1.3.2)
|
59
|
-
rack
|
60
|
-
rack-test (0.6.1)
|
61
|
-
rack (>= 1.0)
|
62
|
-
rails (3.2.8)
|
63
|
-
actionmailer (= 3.2.8)
|
64
|
-
actionpack (= 3.2.8)
|
65
|
-
activerecord (= 3.2.8)
|
66
|
-
activeresource (= 3.2.8)
|
67
|
-
activesupport (= 3.2.8)
|
68
|
-
bundler (~> 1.0)
|
69
|
-
railties (= 3.2.8)
|
70
|
-
railties (3.2.8)
|
71
|
-
actionpack (= 3.2.8)
|
72
|
-
activesupport (= 3.2.8)
|
73
|
-
rack-ssl (~> 1.3.2)
|
74
|
-
rake (>= 0.8.7)
|
75
|
-
rdoc (~> 3.4)
|
76
|
-
thor (>= 0.14.6, < 2.0)
|
77
|
-
rake (0.9.2.2)
|
78
|
-
rdoc (3.12)
|
79
|
-
json (~> 1.4)
|
80
|
-
rspec (2.11.0)
|
81
|
-
rspec-core (~> 2.11.0)
|
82
|
-
rspec-expectations (~> 2.11.0)
|
83
|
-
rspec-mocks (~> 2.11.0)
|
84
|
-
rspec-core (2.11.1)
|
85
|
-
rspec-expectations (2.11.3)
|
86
|
-
diff-lcs (~> 1.1.3)
|
87
|
-
rspec-mocks (2.11.3)
|
88
|
-
rspec-rails (2.11.0)
|
89
|
-
actionpack (>= 3.0)
|
90
|
-
activesupport (>= 3.0)
|
91
|
-
railties (>= 3.0)
|
92
|
-
rspec (~> 2.11.0)
|
93
|
-
sprockets (2.1.3)
|
94
|
-
hike (~> 1.2)
|
95
|
-
rack (~> 1.0)
|
96
|
-
tilt (~> 1.1, != 1.3.0)
|
97
|
-
thor (0.16.0)
|
98
|
-
tilt (1.3.3)
|
99
|
-
treetop (1.4.10)
|
100
|
-
polyglot
|
101
|
-
polyglot (>= 0.3.1)
|
102
|
-
tzinfo (0.3.33)
|
103
|
-
|
104
|
-
PLATFORMS
|
105
|
-
ruby
|
106
|
-
|
107
|
-
DEPENDENCIES
|
108
|
-
bulk_data_methods!
|
data/README
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
bulk_data_methods
|
2
|
-
==================
|
3
|
-
MixIn used to extend ActiveRecord::Base classes implementing bulk insert and update operations
|
4
|
-
through {#create_many} and {#update_many}.
|
5
|
-
|
6
|
-
Examples
|
7
|
-
========
|
8
|
-
|
9
|
-
class Company < ActiveRecord::Base
|
10
|
-
extend BulkMethodsMixin
|
11
|
-
end
|
12
|
-
__________________________
|
13
|
-
BULK creation of many rows:
|
14
|
-
|
15
|
-
example no options used
|
16
|
-
rows = [
|
17
|
-
{ :name => 'Keith', :salary => 1000 },
|
18
|
-
{ :name => 'Alex', :salary => 2000 }
|
19
|
-
]
|
20
|
-
Employee.create_many(rows)
|
21
|
-
|
22
|
-
example with :returning option to returns key value
|
23
|
-
rows = [
|
24
|
-
{ :name => 'Keith', :salary => 1000 },
|
25
|
-
{ :name => 'Alex', :salary => 2000 }
|
26
|
-
]
|
27
|
-
options = { :returning => [:id] }
|
28
|
-
Employee.create_many(rows, options)
|
29
|
-
|
30
|
-
example with :slice_size option (will generate two insert queries)
|
31
|
-
rows = [
|
32
|
-
{ :name => 'Keith', :salary => 1000 },
|
33
|
-
{ :name => 'Alex', :salary => 2000 },
|
34
|
-
{ :name => 'Mark', :salary => 3000 }
|
35
|
-
]
|
36
|
-
options = { :slice_size => 2 }
|
37
|
-
Employee.create_many(rows, options)
|
38
|
-
_________________________
|
39
|
-
BULK updates of many rows:
|
40
|
-
|
41
|
-
example using "set_array" to add the value of "salary" to the specific employee's salary the default where clause matches IDs so, it works here.
|
42
|
-
rows = [
|
43
|
-
{ :id => 1, :salary => 1000 },
|
44
|
-
{ :id => 10, :salary => 2000 },
|
45
|
-
{ :id => 23, :salary => 2500 }
|
46
|
-
]
|
47
|
-
options = { :set_array => '"salary = datatable.salary"' }
|
48
|
-
Employee.update_many(rows, options)
|
49
|
-
|
50
|
-
example using where clause to match salary.
|
51
|
-
rows = [
|
52
|
-
{ :id => 1, :salary => 1000, :company_id => 10 },
|
53
|
-
{ :id => 10, :salary => 2000, :company_id => 12 },
|
54
|
-
{ :id => 23, :salary => 2500, :company_id => 5 }
|
55
|
-
]
|
56
|
-
options = {
|
57
|
-
:set_array => '"company_id = datatable.company_id"',
|
58
|
-
:where => '"#{table_name}.salary = datatable.salary"'
|
59
|
-
}
|
60
|
-
Employee.update_many(rows, options)
|
61
|
-
|
62
|
-
example setting where clause to the KEY of the hash passed in and the set_array is generated from the VALUES
|
63
|
-
rows = {
|
64
|
-
{ :id => 1 } => { :salary => 100000, :company_id => 10 },
|
65
|
-
{ :id => 10 } => { :salary => 110000, :company_id => 12 },
|
66
|
-
{ :id => 23 } => { :salary => 90000, :company_id => 5 }
|
67
|
-
}
|
68
|
-
Employee.update_many(rows)
|