bulk_update 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +30 -15
- data/lib/bulk_update/active_record_inflections.rb +22 -5
- data/lib/bulk_update/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -22,13 +22,15 @@ Or install it yourself as:
|
|
22
22
|
### Bulk insert
|
23
23
|
|
24
24
|
Bulk insert inserts a large amount of data into as SQL-Bulk-Inserts. Example:
|
25
|
+
|
25
26
|
columns = [:name, :value]
|
26
27
|
values = [['name1', 'value1'], ['name2', 'value2'], ['name3', 'value3']]
|
27
28
|
Model.bulk_insert columns, values
|
28
29
|
|
29
30
|
### Bulk update
|
30
31
|
|
31
|
-
Bulk update updates a large amount of data. Update means, it creates new records, updates existing records which have changed and deletes old records. This is all done with ActiveRecord which means, all callbacks are executed.
|
32
|
+
Bulk update updates a large amount of data. Update means, it creates new records, updates existing records which have changed and deletes old records. This is all done with ActiveRecord which means, all callbacks are executed. The difference between the old and the new records are fully discovered by SQL.
|
33
|
+
|
32
34
|
You have to provide a columns as a key, which is used determine which records are new, have changed or has to be deleted. Only the values provided in the array 'values' are compared and will be updated. Example:
|
33
35
|
|
34
36
|
columns = [:name, :value]
|
@@ -37,13 +39,13 @@ You have to provide a columns as a key, which is used determine which records ar
|
|
37
39
|
|
38
40
|
You have now the following entries in your database:
|
39
41
|
<pre>
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
+----+-------+--------+-----------+------------+
|
43
|
+
| id | name | value | timestamp | updated_at |
|
44
|
+
+----+-------+--------+-----------+------------+
|
45
|
+
| 0 | name1 | value1 | t1 | t1 |
|
46
|
+
| 1 | name2 | value2 | t1 | t1 |
|
47
|
+
| 2 | name3 | value3 | t1 | t1 |
|
48
|
+
+----+-------+--------+-----------+------------+
|
47
49
|
</pre>
|
48
50
|
|
49
51
|
If you now do a bulk update:
|
@@ -53,15 +55,28 @@ If you now do a bulk update:
|
|
53
55
|
|
54
56
|
You have now the following entries in your database:
|
55
57
|
<pre>
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
+----+-------+----------+-----------+------------+
|
59
|
+
| id | name | value | timestamp | updated_at |
|
60
|
+
+----+-------+----------+-----------+------------+
|
61
|
+
| 0 | name1 | value1.1 | t1 | t2 |
|
62
|
+
| 1 | name2 | value2 | t1 | t1 |
|
63
|
+
| 3 | name4 | value4.1 | t2 | t2 |
|
64
|
+
+----+-------+----------+-----------+------------+
|
63
65
|
</pre>
|
64
66
|
|
67
|
+
## How it works
|
68
|
+
|
69
|
+
### Bulk insert
|
70
|
+
|
71
|
+
Bulk insert uses the bulk insert feature of SQL (`INSERT INTO tbl_name (col1,col2,col3) VALUES(v1,v2,v3),(v4,v5,v6),(v7,v8,v9);`)
|
72
|
+
|
73
|
+
You can specify the max records per insert with the argument `:max_records_per_insert` (default is 100). After these amount of records, the SQL is sent to the database.
|
74
|
+
|
75
|
+
### Bulk update
|
76
|
+
|
77
|
+
First, a temp-table will be created with the same structure as the original table. Then, all new records are inserted by bulk-inserts into the temp-table.
|
78
|
+
When the temp table was loaded, the difference between these 2 tables are discovered in 3 steps: New records, changed records and deleted records.
|
79
|
+
All new, changed and deleted records are handled by ActiveRecord. This ensures, all callbacks get executed as defined.
|
65
80
|
|
66
81
|
## Contributing
|
67
82
|
|
@@ -8,6 +8,8 @@ module BulkUpdate
|
|
8
8
|
when 'sqlite3'
|
9
9
|
ActiveRecord::Base.connection.execute "CREATE TABLE `#{args[:to]}` AS SELECT * FROM `#{table_name}` LIMIT 1"
|
10
10
|
ActiveRecord::Base.connection.execute "DELETE FROM `#{args[:to]}`"
|
11
|
+
when 'postgresql'
|
12
|
+
ActiveRecord::Base.connection.execute "CREATE TABLE \"#{args[:to]}\" (LIKE \"#{table_name}\" INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES);"
|
11
13
|
else
|
12
14
|
ActiveRecord::Base.connection.execute "CREATE TABLE `#{args[:to]}` LIKE `#{table_name}`"
|
13
15
|
end
|
@@ -53,8 +55,14 @@ module BulkUpdate
|
|
53
55
|
|
54
56
|
if table_name
|
55
57
|
# Create header for insert with all column names
|
56
|
-
|
57
|
-
|
58
|
+
case ActiveRecord::Base.connection_config[:adapter]
|
59
|
+
when 'postgresql'
|
60
|
+
columns = columns.map! { |c| "\"#{c}\"" }
|
61
|
+
insert_head = "INSERT INTO \"#{table}\" (#{columns.join(', ')})"
|
62
|
+
else
|
63
|
+
columns = columns.map!{ |c| "`#{c}`" }
|
64
|
+
insert_head = "INSERT INTO `#{table}` (#{columns.join(', ')})"
|
65
|
+
end
|
58
66
|
|
59
67
|
# Create inserts
|
60
68
|
inserts = []
|
@@ -143,6 +151,7 @@ module BulkUpdate
|
|
143
151
|
new_records = []
|
144
152
|
keys_to_log = []
|
145
153
|
results.each do |attributes|
|
154
|
+
attributes = attributes2array(attributes)
|
146
155
|
new_records << result2hash(attributes, exclude)
|
147
156
|
keys_to_log << new_records.last[key.to_sym]
|
148
157
|
end
|
@@ -188,15 +197,17 @@ module BulkUpdate
|
|
188
197
|
|
189
198
|
# Generate and execute SQL-Statement
|
190
199
|
condition = "#{conditions.join(' AND ')} AND (#{conditions2.join(' OR ')})"
|
191
|
-
|
200
|
+
compare_columns = attribute_names.select { |e| e != 'id' }.map { |e| "#{compare_table}.#{e}" }.join(', ')
|
201
|
+
sql = "SELECT #{model.table_name}.id, #{compare_columns} FROM #{model.table_name}, #{compare_table} WHERE #{condition}"
|
192
202
|
results = ActiveRecord::Base.connection.execute sql
|
193
203
|
|
194
204
|
# Generate Hash with id as the key and values as a Hashes of all changed records
|
195
205
|
results_hash = {}
|
196
206
|
keys_to_log = []
|
197
207
|
results.each do |attributes|
|
208
|
+
attributes = attributes2array(attributes)
|
198
209
|
id = attributes[0]
|
199
|
-
results_hash[id] = result2hash attributes, exclude
|
210
|
+
results_hash[id] = result2hash attributes, exclude
|
200
211
|
keys_to_log << (args[:debug] ? model.find(id).send(key) : id)
|
201
212
|
end
|
202
213
|
args[:logger].info "Change Records for Model #{model.to_s}: #{keys_to_log.join(', ')}" unless keys_to_log.blank? || args[:logger].blank?
|
@@ -237,6 +248,7 @@ module BulkUpdate
|
|
237
248
|
deleted_records = []
|
238
249
|
keys_to_log = []
|
239
250
|
results.each do |attributes|
|
251
|
+
attributes = attributes2array(attributes)
|
240
252
|
deleted_records << attributes[0]
|
241
253
|
keys_to_log << attributes[1]
|
242
254
|
end
|
@@ -248,7 +260,7 @@ module BulkUpdate
|
|
248
260
|
private
|
249
261
|
|
250
262
|
|
251
|
-
def result2hash
|
263
|
+
def result2hash(attributes, exclude, attribute_nr = 0)
|
252
264
|
hash = {}
|
253
265
|
attribute_names.each do |an|
|
254
266
|
hash[an.to_sym] = attributes[attribute_nr] unless exclude.include?(an)
|
@@ -257,5 +269,10 @@ module BulkUpdate
|
|
257
269
|
hash
|
258
270
|
end
|
259
271
|
|
272
|
+
|
273
|
+
def attributes2array(attributes)
|
274
|
+
ActiveRecord::Base.connection_config[:adapter] == 'postgresql' ? attributes.map{ |e| e.last } : attributes
|
275
|
+
end
|
276
|
+
|
260
277
|
end
|
261
278
|
end
|
data/lib/bulk_update/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bulk_update
|
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-01-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|