bulk_data_methods 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|