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 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
- | id | name | value |
42
- +----+----------------+
43
- | 0 | name1 | value1 |
44
- | 1 | name2 | value2 |
45
- | 2 | name3 | value3 |
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
- | id | name | value |
58
- +----+------------------+
59
- | 0 | name1 | value1.1 |
60
- | 1 | name2 | value2 |
61
- | 3 | name4 | value4.1 |
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
- columns = columns.clone.map!{ |c| "`#{c}`" }
57
- insert_head = "INSERT INTO `#{table}` (#{columns.join(', ')})"
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
- sql = "SELECT #{model.table_name}.id, #{compare_table}.* FROM #{model.table_name}, #{compare_table} WHERE #{condition}"
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, 1
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 attributes, exclude, attribute_nr = 0
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
@@ -1,3 +1,3 @@
1
1
  module BulkUpdate
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
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.0.0
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: 2012-08-29 00:00:00.000000000 Z
12
+ date: 2013-01-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord