mass_record 0.0.1 → 0.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/lib/mass_record/version.rb +1 -1
- data/lib/mass_record.rb +322 -84
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5eaa64bad4860bb2f6d3630a437f539b02e94598
|
4
|
+
data.tar.gz: c46e691401efbe81bd591d98eceda9166edc1f27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33bfc72ba9cc48048035faa29702ea843fe50e3dcece44c5017c683fd92876bd665a2878c81c6f5d666ccf6e369c850fea9f6015e54b00d31703112ebf96460e
|
7
|
+
data.tar.gz: 2c35b274cf2f33e2c5971dadf0d1926679956781a9f192397a48577c1c1cb15ade952f9692f300516d929d85a082c27c95c9953d2feca1c67c133a8819b35bd9
|
data/lib/mass_record/version.rb
CHANGED
data/lib/mass_record.rb
CHANGED
@@ -9,6 +9,7 @@ module MassRecord
|
|
9
9
|
self.path[:errored_queries] = "tmp/#{Rails.env}"
|
10
10
|
self.path[:completed_queries] = "tmp/#{Rails.env}"
|
11
11
|
|
12
|
+
|
12
13
|
module Actions
|
13
14
|
path = {}
|
14
15
|
folder_path = "tmp/#{Rails.env}"
|
@@ -17,6 +18,27 @@ module MassRecord
|
|
17
18
|
path[:errored_queries] = "#{path[:queries]}/errored"
|
18
19
|
path[:completed_queries] = "#{path[:queries]}/completed"
|
19
20
|
|
21
|
+
class IndividualError < Exception
|
22
|
+
attr_accessor :operation,:table,:json_object,:original_exception,:backtrace,:backtrace_locations,:cause,:exception,:message
|
23
|
+
|
24
|
+
def initialize exception, json_object:nil, operation:nil, table:nil
|
25
|
+
self.backtrace = exception.backtrace
|
26
|
+
self.backtrace_locations = exception.backtrace_locations
|
27
|
+
self.cause = exception.cause
|
28
|
+
self.exception = exception.exception
|
29
|
+
self.message = exception.message
|
30
|
+
|
31
|
+
self.original_exception = exception
|
32
|
+
self.json_object = json_object
|
33
|
+
self.operation = operation
|
34
|
+
self.table = table
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
original_exception.to_s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
20
42
|
# accepts an array of objects with the option to specify what rails operation to perform
|
21
43
|
def queue_for_quick_query object_array,
|
22
44
|
operation: :save,
|
@@ -45,7 +67,9 @@ module MassRecord
|
|
45
67
|
},synonyms:{
|
46
68
|
insert: [:create, :new, :add, :insert, :post],
|
47
69
|
update: [:update,:edit,:modify,:put,:patch],
|
48
|
-
select: [:read,:select,:get]
|
70
|
+
select: [:read,:select,:get],
|
71
|
+
save: [:save],
|
72
|
+
delete: [:delete]
|
49
73
|
},folder:{
|
50
74
|
queued:path[:queued_queries],
|
51
75
|
errored:path[:errored_queries],
|
@@ -82,25 +106,271 @@ module MassRecord
|
|
82
106
|
errors[:insert] = mass_insert_by_table json_objects.select{|x| synonyms[:insert].include? x[key[:operation]].to_sym.downcase}, key:key
|
83
107
|
elsif synonyms[:update].include? op
|
84
108
|
errors[:update] = mass_update_by_table json_objects.select{|x| synonyms[:update].include? x[key[:operation]].to_sym.downcase}, key:key
|
85
|
-
elsif
|
109
|
+
elsif synonyms[:save].include? op # needs to intelligently determine if the order already exists, insert if not, update if so
|
86
110
|
errors[:save] = mass_save_by_table json_objects.select{|x| :save == x[key[:operation]].to_sym.downcase}, key:key
|
87
|
-
elsif
|
111
|
+
elsif synonyms[:delete].include? op
|
88
112
|
elsif synonyms[:select].include? op
|
89
113
|
else
|
90
114
|
end
|
91
115
|
end
|
92
116
|
|
93
117
|
# close database connection
|
94
|
-
database_connection.close
|
95
118
|
|
96
119
|
# move to appropriate folder and remove '.processing' from the filename
|
120
|
+
errors_present = errors.any?{|op,tables| tables.has_key? :run_time or tables.any?{|table,col_sets| !table.blank?}}
|
121
|
+
errored_objects = collect_errored_objects found_in:errors, from:json_objects, key:key, synonyms:synonyms if errors_present
|
122
|
+
|
123
|
+
individual_errors = errors_present ? (query_per_object errored_objects, key:key, synonyms:synonyms) : []
|
124
|
+
database_connection.close
|
125
|
+
|
97
126
|
files = Dir.foreach(folder[:queued]).collect{|x| x}.keep_if{|y|y=~/\.json\.processing$/i}
|
98
|
-
errors_present = errors.any?{|op,h| h.any?{|table,a| a.count > 0 }}
|
99
127
|
files.each{|x| File.rename "#{folder[:queued]}/#{x}","#{errors_present ? folder[:errored] : folder[:completed]}/group_#{file_tag}_#{x.gsub /\.processing$/,''}"}
|
100
128
|
|
129
|
+
individual_errors += collect_run_time_errors found_in:errors
|
130
|
+
return individual_errors
|
131
|
+
end
|
132
|
+
|
133
|
+
def collect_run_time_errors found_in:{}, loop_limit:10
|
134
|
+
return [] if found_in.blank?
|
135
|
+
run_time_errors = []
|
136
|
+
|
137
|
+
while found_in.is_a? Hash and loop_limit > 0
|
138
|
+
loop_limit -= 1
|
139
|
+
found_in.each do |k,v|
|
140
|
+
if k == :run_time
|
141
|
+
run_time_errors << v
|
142
|
+
else
|
143
|
+
run_time_errors += collect_run_time_errors found_in:v, loop_limit:loop_limit
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
return run_time_errors
|
148
|
+
end
|
149
|
+
|
150
|
+
def collect_errored_objects found_in:{}, from:[], key:{}, synonyms:{}
|
151
|
+
return [] if found_in.blank? or from.blank?
|
152
|
+
|
153
|
+
errored_objects = []
|
154
|
+
|
155
|
+
found_in.each do |operation, tables|
|
156
|
+
unless operation == :run_time
|
157
|
+
tables.each do |table, column_sets|
|
158
|
+
unless table == :run_time
|
159
|
+
column_sets.each do |column_set,error|
|
160
|
+
unless column_set == :run_time
|
161
|
+
if error.is_a? Exception and error.is_a? ActiveRecord::StatementInvalid
|
162
|
+
# collect objects by operation, table, and column set
|
163
|
+
operation_terms = synonyms[operation.to_sym]
|
164
|
+
errored_objects += from.select{|x| table.to_s == x[key[:table]].to_s and operation_terms.include? x[key[:operation]].to_sym and x[key[:object]].keys.sort == column_set.sort}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
return errored_objects
|
174
|
+
end
|
175
|
+
|
176
|
+
def query_per_object objects, key:{}, synonyms:{}
|
177
|
+
# get all operations and tables in use
|
178
|
+
operations = objects.collect{|x| x[key[:operation]].to_sym}.to_set.to_a
|
179
|
+
|
180
|
+
# construct queries
|
181
|
+
errors = []
|
182
|
+
operations.each do |op|
|
183
|
+
if synonyms[:insert].include? op
|
184
|
+
errors += insert_by_table objects.select{|x| synonyms[:insert].include? x[key[:operation]].to_sym.downcase}, key:key
|
185
|
+
elsif synonyms[:update].include? op
|
186
|
+
errors += update_by_table objects.select{|x| synonyms[:update].include? x[key[:operation]].to_sym.downcase}, key:key
|
187
|
+
elsif synonyms[:save].include? op # needs to intelligently determine if the order already exists, insert if not, update if so
|
188
|
+
errors += save_by_table objects.select{|x| :save == x[key[:operation]].to_sym.downcase}, key:key
|
189
|
+
elsif synonyms[:delete].include? op
|
190
|
+
elsif synonyms[:select].include? op
|
191
|
+
else
|
192
|
+
end
|
193
|
+
end
|
101
194
|
return errors
|
102
195
|
end
|
103
196
|
|
197
|
+
def update_by_table json_objects, key:{}
|
198
|
+
begin
|
199
|
+
tables = json_objects.collect{|x| x[key[:table]]}.to_set.to_a
|
200
|
+
|
201
|
+
errors = []
|
202
|
+
tables.each do |table|
|
203
|
+
hashes = json_objects.select{|o| o[key[:table]] == table}.collect{|x| x[key[:object]]}
|
204
|
+
errors += update hashes, into:table
|
205
|
+
end
|
206
|
+
return errors
|
207
|
+
rescue Exception => e
|
208
|
+
return ((defined? errors) ? (errors << IndividualError.new(e,operation:"update")) : [IndividualError.new(e,operation:"update")])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def sort_save_operations from:nil, for_table:nil, key:{}
|
213
|
+
return {} if from.blank? or for_table.blank?
|
214
|
+
table = for_table
|
215
|
+
hashes = from.select{|o| o[key[:table]] == table}.collect{|x| x[key[:object]]}
|
216
|
+
model = table.classify.constantize
|
217
|
+
pk = model.primary_key
|
218
|
+
|
219
|
+
# organize hashes based on whether they exist (based on their primary key(s)) in the table or not
|
220
|
+
if pk.is_a? Array
|
221
|
+
ids = hashes.reject{|x| pk.any?{|k| x[k].blank?}}.collect{|x| x.select{|k,v| pk.include? k}} # only accept full sets of pk's
|
222
|
+
where_clauses = []
|
223
|
+
ids.each do |id|
|
224
|
+
equivalence_clauses = []
|
225
|
+
id.each do |k,v|
|
226
|
+
equivalence_clauses << "#{ActiveRecord::Base.connection.quote_column_name k} = #{ActiveRecord::Base.connection.quote(ActiveRecord::Base.connection.type_cast(v, model.column_types[k]))}"
|
227
|
+
end
|
228
|
+
where_clauses << "(#{equivalence_clauses.join ' and '})"
|
229
|
+
end
|
230
|
+
existing_id_sets = ActiveRecord::Base.connection.execute("SELECT #{pk.join ', '} FROM #{table} WHERE #{where_clauses.join ' OR '}").collect{|x| Hash[x.map.with_index{|x,i| [pk[i],x]}]}
|
231
|
+
insert_hashes = hashes.reject{|h| existing_id_sets.any?{|set| h == h.merge(set)}}
|
232
|
+
update_hashes = hashes.select{|h| existing_id_sets.any?{|set| h == h.merge(set)}}
|
233
|
+
else
|
234
|
+
ids = hashes.reject{|x| x[pk].blank?}.collect{|x| x[pk]} # should not include null values
|
235
|
+
existing_ids = ActiveRecord::Base.connection.execute("SELECT #{pk} FROM #{table} WHERE #{pk} in ('#{ids.join "','"}')").collect{|x| x.first.to_s}
|
236
|
+
insert_hashes = hashes.reject{|x| existing_ids.include? x[pk].to_s}
|
237
|
+
update_hashes = hashes.select{|x| existing_ids.include? x[pk].to_s}
|
238
|
+
end
|
239
|
+
|
240
|
+
return {insert:insert_hashes,update:update_hashes}
|
241
|
+
end
|
242
|
+
|
243
|
+
def save_by_table json_objects, key:{}
|
244
|
+
begin
|
245
|
+
tables = json_objects.collect{|x| x[key[:table]]}.to_set.to_a
|
246
|
+
|
247
|
+
errors = []
|
248
|
+
tables.each do |table|
|
249
|
+
# sort the hashes by operation type
|
250
|
+
sorted_hashes = sort_save_operations from:json_objects, for_table:table, key:key
|
251
|
+
|
252
|
+
# perform the appropriate operations
|
253
|
+
model = table.classify.constantize
|
254
|
+
errors += update sorted_hashes[:update], into:model unless sorted_hashes[:update].blank?
|
255
|
+
errors += insert sorted_hashes[:insert], into:model unless sorted_hashes[:insert].blank?
|
256
|
+
end
|
257
|
+
return errors
|
258
|
+
rescue Exception => e
|
259
|
+
return ((defined? errors) ? (errors << IndividualError.new(e,operation:"save")) : [IndividualError.new(e,operation:"save")])
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def insert_by_table json_objects, key:{}
|
264
|
+
begin
|
265
|
+
tables = json_objects.collect{|x| x[key[:table]]}.to_set.to_a
|
266
|
+
|
267
|
+
errors = []
|
268
|
+
tables.each do |table|
|
269
|
+
hashes = json_objects.select{|o| o[key[:table]] == table}.collect{|x| x[key[:object]]}
|
270
|
+
errors += insert hashes, into:table
|
271
|
+
end
|
272
|
+
return errors
|
273
|
+
rescue Exception => e
|
274
|
+
return ((defined? errors) ? (errors << IndividualError.new(e,operation:"insert")) : [IndividualError.new(e,operation:"insert")])
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def sql_for_insert hash, into:nil
|
279
|
+
return nil if hash.blank? or into.blank?
|
280
|
+
model = into.is_a?(String) ? into.classify.constantize : into
|
281
|
+
id_column_name = model.primary_key
|
282
|
+
created_at = model.attribute_alias?("created_at") ? model.attribute_alias("created_at") : "created_at"
|
283
|
+
updated_at = model.attribute_alias?("updated_at") ? model.attribute_alias("updated_at") : "updated_at"
|
284
|
+
t = model.arel_table
|
285
|
+
|
286
|
+
h = hash.clone # use a copy of hash, so it doesn't change the original data
|
287
|
+
|
288
|
+
# assemble an individual query
|
289
|
+
im = Arel::InsertManager.new(ActiveRecord::Base)
|
290
|
+
unless id_column_name.is_a? Array # don't modify the id fields if there are concatenated primary keys
|
291
|
+
h.delete id_column_name if model.columns.select{|x| x.name == id_column_name}.first.extra == 'auto_increment' or h[id_column_name].blank?
|
292
|
+
end
|
293
|
+
h = convert_to_db_format h, model:model, created_at:created_at, updated_at:updated_at
|
294
|
+
pairs = h.collect do |k,v|
|
295
|
+
[t[k.to_sym],v]
|
296
|
+
end
|
297
|
+
im.insert pairs
|
298
|
+
im.to_sql
|
299
|
+
end
|
300
|
+
|
301
|
+
def sql_for_update hash, into:nil
|
302
|
+
return nil if hash.blank? or into.blank?
|
303
|
+
model = into.is_a?(String) ? into.classify.constantize : into
|
304
|
+
id_column_name = model.primary_key
|
305
|
+
created_at = model.attribute_alias?("created_at") ? model.attribute_alias("created_at") : "created_at"
|
306
|
+
updated_at = model.attribute_alias?("updated_at") ? model.attribute_alias("updated_at") : "updated_at"
|
307
|
+
t = model.arel_table
|
308
|
+
|
309
|
+
h = hash.clone # use a copy of hash, so it doesn't change the original data
|
310
|
+
h = convert_to_db_format h, model:model, created_at:created_at, updated_at:updated_at
|
311
|
+
|
312
|
+
# assemble an individual query
|
313
|
+
um = Arel::UpdateManager.new(ActiveRecord::Base)
|
314
|
+
um.where(t[id_column_name.to_sym].eq(h[id_column_name])) unless id_column_name.is_a? Array
|
315
|
+
id_column_name.each{|key| um.where t[key.to_sym].eq(h[key])} if id_column_name.is_a? Array
|
316
|
+
um.table(t)
|
317
|
+
id_column_name.each{|name| h.delete name} if id_column_name.is_a? Array # don't allow modification of the primary keys
|
318
|
+
h.delete id_column_name if id_column_name.is_a? String # don't allow modification of the primary keys
|
319
|
+
pairs = h.collect do |k,v|
|
320
|
+
[t[k.to_sym],v]
|
321
|
+
end
|
322
|
+
um.set pairs
|
323
|
+
um.to_sql
|
324
|
+
end
|
325
|
+
|
326
|
+
def update hashes, into:nil
|
327
|
+
begin
|
328
|
+
return false if hashes.blank? or into.blank?
|
329
|
+
hashes = [hashes] unless hashes.is_a? Array
|
330
|
+
|
331
|
+
errors = []
|
332
|
+
# create an array of single insert queries
|
333
|
+
hashes.each do |hash|
|
334
|
+
sql = sql_for_insert hash, into:into
|
335
|
+
|
336
|
+
begin
|
337
|
+
query sql
|
338
|
+
rescue Exception => e
|
339
|
+
puts e.message
|
340
|
+
errors << IndividualError.new(e,table:into,operation:"update",json_object:hash)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
return errors
|
344
|
+
rescue Exception => e
|
345
|
+
return (defined? errors) ? (errors << IndividualError.new(e, table:into, operation:"update")) : [IndividualError.new( e, table:into, operation:"update")]
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def insert hashes, into:nil
|
350
|
+
begin
|
351
|
+
return false if hashes.blank? or into.blank?
|
352
|
+
hashes = [hashes] unless hashes.is_a? Array
|
353
|
+
|
354
|
+
errors = []
|
355
|
+
# create an array of single insert queries
|
356
|
+
hashes.each do |hash|
|
357
|
+
sql = sql_for_insert hash, into:into
|
358
|
+
|
359
|
+
begin
|
360
|
+
query sql
|
361
|
+
rescue Exception => e
|
362
|
+
puts e.message
|
363
|
+
errors << IndividualError.new(e,table:into,operation:"insert",json_object:hash)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
# reparse the queries and execute them
|
368
|
+
return errors
|
369
|
+
rescue Exception => e
|
370
|
+
return (defined? errors) ? (errors << IndividualError.new(e, table:into, operation:"insert")) : [IndividualError.new( e, table:into, operation:"insert")]
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
104
374
|
def mass_validate objects
|
105
375
|
# TODO: write logic, should return only valid objects
|
106
376
|
return objects
|
@@ -113,12 +383,14 @@ module MassRecord
|
|
113
383
|
errors = {}
|
114
384
|
tables.each do |table|
|
115
385
|
hashes = json_objects.select{|o| o[key[:table]] == table}.collect{|x| x[key[:object]]}
|
116
|
-
|
386
|
+
|
387
|
+
errors[table.to_sym] = {} unless errors[table.to_sym].is_a? Hash
|
388
|
+
errors[table.to_sym].merge! mass_update hashes, into:table
|
117
389
|
end
|
118
390
|
return errors
|
119
391
|
rescue Exception => e
|
120
|
-
return {
|
121
|
-
errors[:
|
392
|
+
return {run_time:e} unless defined? errors
|
393
|
+
errors[:run_time] = e if defined? errors
|
122
394
|
return errors
|
123
395
|
end
|
124
396
|
end
|
@@ -129,40 +401,19 @@ module MassRecord
|
|
129
401
|
|
130
402
|
errors = {}
|
131
403
|
tables.each do |table|
|
132
|
-
|
133
|
-
|
134
|
-
pk = model.primary_key
|
135
|
-
|
136
|
-
# organize hashes based on whether they exist (based on their primary key(s)) in the table or not
|
137
|
-
if pk.is_a? Array
|
138
|
-
ids = hashes.reject{|x| pk.any?{|k| x[k].blank?}}.collect{|x| x.select{|k,v| pk.include? k}} # only accept full sets of pk's
|
139
|
-
where_clauses = []
|
140
|
-
ids.each do |id|
|
141
|
-
equivalence_clauses = []
|
142
|
-
id.each do |k,v|
|
143
|
-
equivalence_clauses << "#{ActiveRecord::Base.connection.quote_column_name k} = #{ActiveRecord::Base.connection.quote(ActiveRecord::Base.connection.type_cast(v, model.column_types[k]))}"
|
144
|
-
end
|
145
|
-
where_clauses << "(#{equivalence_clauses.join ' and '})"
|
146
|
-
end
|
147
|
-
existing_id_sets = ActiveRecord::Base.connection.execute("SELECT #{pk.join ', '} FROM #{table} WHERE #{where_clauses.join ' OR '}").collect{|x| Hash[x.map.with_index{|x,i| [pk[i],x]}]}
|
148
|
-
insert_hashes = hashes.reject{|h| existing_id_sets.any?{|set| h == h.merge(set)}}
|
149
|
-
update_hashes = hashes.select{|h| existing_id_sets.any?{|set| h == h.merge(set)}}
|
150
|
-
else
|
151
|
-
ids = hashes.reject{|x| x[pk].blank?}.collect{|x| x[pk]} # should not include null values
|
152
|
-
existing_ids = ActiveRecord::Base.connection.execute("SELECT #{pk} FROM #{table} WHERE #{pk} in ('#{ids.join "','"}')").collect{|x| x.first.to_s}
|
153
|
-
insert_hashes = hashes.reject{|x| existing_ids.include? x[pk].to_s}
|
154
|
-
update_hashes = hashes.select{|x| existing_ids.include? x[pk].to_s}
|
155
|
-
end
|
404
|
+
# sort the hashes by operation type
|
405
|
+
sorted_hashes = sort_save_operations from:json_objects, for_table:table, key:key
|
156
406
|
|
157
407
|
# perform the appropriate operations
|
158
|
-
|
159
|
-
errors[table.to_sym]
|
160
|
-
errors[table.to_sym]
|
161
|
-
|
408
|
+
model = table.classify.constantize
|
409
|
+
errors[table.to_sym] = {}
|
410
|
+
errors[table.to_sym].merge! mass_update sorted_hashes[:update], into:model unless sorted_hashes[:update].blank?
|
411
|
+
errors[table.to_sym].merge! mass_insert sorted_hashes[:insert], into:model unless sorted_hashes[:insert].blank?
|
412
|
+
end
|
162
413
|
return errors
|
163
414
|
rescue Exception => e
|
164
|
-
return {
|
165
|
-
errors[:
|
415
|
+
return {run_time:e} unless defined? errors
|
416
|
+
errors[:run_time] = e if defined? errors
|
166
417
|
return errors
|
167
418
|
end
|
168
419
|
end
|
@@ -175,8 +426,8 @@ module MassRecord
|
|
175
426
|
id_column_name = model.primary_key
|
176
427
|
created_at = model.attribute_alias?("created_at") ? model.attribute_alias("created_at") : "created_at"
|
177
428
|
updated_at = model.attribute_alias?("updated_at") ? model.attribute_alias("updated_at") : "updated_at"
|
178
|
-
solitary_queries = []
|
179
|
-
t = model.arel_table
|
429
|
+
solitary_queries = [] # I think this can be deleted
|
430
|
+
t = model.arel_table # I think this can be deleted
|
180
431
|
|
181
432
|
# organize by unique column sets
|
182
433
|
unique_column_sets = {}
|
@@ -187,9 +438,9 @@ module MassRecord
|
|
187
438
|
unique_column_sets[column_set] << hash
|
188
439
|
end
|
189
440
|
|
190
|
-
# assemble
|
441
|
+
# assemble and execute queries (1 for each unique set of columns)
|
191
442
|
queries = []
|
192
|
-
|
443
|
+
errors = {}
|
193
444
|
unique_column_sets.each do |column_set, hash_group|
|
194
445
|
if id_column_name.is_a? Array
|
195
446
|
ids = hash_group.collect{|hash| Hash[id_column_name.map.with_index{|column_name,i| [column_name,hash[column_name]] }]}
|
@@ -245,25 +496,21 @@ module MassRecord
|
|
245
496
|
set_columns << "#{column} = CASE #{values.join ' '} END" if id_column_name.is_a? Array
|
246
497
|
end
|
247
498
|
|
248
|
-
queries << "#{update} #{set_columns.join ', '} #{where}"
|
249
|
-
end
|
250
|
-
# [{"id"=>545, "header"=>"new system","details"=>"ya, it worked"},{"id"=>546, "header"=>"sweet system"},{"id"=>547, "header"=>"THAT system","details"=>"ya, it worked"}]
|
251
|
-
errors = []
|
252
|
-
# execute the queries
|
253
|
-
queries.each do |sql|
|
254
499
|
begin
|
255
|
-
query
|
500
|
+
query "#{update} #{set_columns.join ', '} #{where}"
|
256
501
|
rescue Exception => e
|
257
502
|
puts e.message
|
258
|
-
errors
|
503
|
+
errors[column_set] = e
|
259
504
|
end
|
260
|
-
end
|
505
|
+
end
|
506
|
+
|
261
507
|
return errors
|
262
508
|
rescue Exception => e
|
263
|
-
return (defined? errors) ? (errors
|
509
|
+
return (defined? errors) ? (errors.merge!({run_time:e})) : {run_time:e}
|
264
510
|
end
|
265
511
|
end
|
266
512
|
|
513
|
+
|
267
514
|
def mass_insert_by_table json_objects, key:{}
|
268
515
|
begin
|
269
516
|
tables = json_objects.collect{|x| x[key[:table]]}.to_set.to_a
|
@@ -271,12 +518,14 @@ module MassRecord
|
|
271
518
|
errors = {}
|
272
519
|
tables.each do |table|
|
273
520
|
hashes = json_objects.select{|o| o[key[:table]] == table}.collect{|x| x[key[:object]]}
|
274
|
-
|
521
|
+
|
522
|
+
errors[table.to_sym] = {} unless errors[table.to_sym].is_a? Hash
|
523
|
+
errors[table.to_sym].merge! mass_insert hashes, into:table
|
275
524
|
end
|
276
525
|
return errors
|
277
526
|
rescue Exception => e
|
278
|
-
return {
|
279
|
-
errors[:
|
527
|
+
return {run_time:e} unless defined? errors
|
528
|
+
errors[:run_time] = e if defined? errors
|
280
529
|
return errors
|
281
530
|
end
|
282
531
|
end
|
@@ -287,47 +536,36 @@ module MassRecord
|
|
287
536
|
|
288
537
|
# create an array of single insert queries
|
289
538
|
model = into.is_a?(String) ? into.classify.constantize : into
|
290
|
-
id_column_name = model.primary_key
|
291
|
-
created_at = model.attribute_alias?("created_at") ? model.attribute_alias("created_at") : "created_at"
|
292
|
-
updated_at = model.attribute_alias?("updated_at") ? model.attribute_alias("updated_at") : "updated_at"
|
293
|
-
solitary_queries = []
|
294
|
-
t = model.arel_table
|
295
|
-
|
296
|
-
hashes.each do |h|
|
297
|
-
im = Arel::InsertManager.new(ActiveRecord::Base)
|
298
|
-
unless id_column_name.is_a? Array # don't modify the id fields if there are concatenated primary keys
|
299
|
-
h.delete id_column_name if model.columns.select{|x| x.name == id_column_name}.first.extra == 'auto_increment' or h[id_column_name].blank?
|
300
|
-
end
|
301
|
-
h = convert_to_db_format h, model:model, created_at:created_at, updated_at:updated_at
|
302
|
-
pairs = h.collect do |k,v|
|
303
|
-
[t[k.to_sym],v]
|
304
|
-
end
|
305
|
-
im.insert pairs
|
306
|
-
solitary_queries << im.to_sql
|
307
|
-
end
|
308
|
-
|
309
|
-
# group the queries by unique column lists
|
310
539
|
concentrated_queries = {}
|
311
540
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
541
|
+
hashes.each do |hash|
|
542
|
+
original_key_set = hash.keys.sort
|
543
|
+
sql = sql_for_insert hash, into:model
|
544
|
+
|
545
|
+
# group the queries by unique column lists
|
546
|
+
into_clause = sql.gsub /\s*VALUES.*$/,''
|
547
|
+
value_clause = sql.gsub(/^.*VALUES\s*/,'')
|
548
|
+
|
549
|
+
concentrated_queries[original_key_set] = {} unless concentrated_queries[original_key_set].is_a? Hash
|
550
|
+
concentrated_queries[original_key_set][:into] = into_clause
|
551
|
+
concentrated_queries[original_key_set][:values] = [] unless concentrated_queries[original_key_set][:values].is_a? Array
|
552
|
+
concentrated_queries[original_key_set][:values] << value_clause
|
316
553
|
end
|
317
554
|
|
318
|
-
errors =
|
555
|
+
errors = {}
|
556
|
+
|
319
557
|
# reparse the queries and execute them
|
320
|
-
concentrated_queries.each do |
|
558
|
+
concentrated_queries.each do |column_set,clauses|
|
321
559
|
begin
|
322
|
-
query "#{
|
560
|
+
query "#{clauses[:into]} VALUES #{clauses[:values].join(", ")}"
|
323
561
|
rescue Exception => e
|
324
562
|
puts e.message
|
325
|
-
errors
|
563
|
+
errors[column_set] = e
|
326
564
|
end
|
327
565
|
end
|
328
566
|
return errors
|
329
567
|
rescue Exception => e
|
330
|
-
return (defined? errors) ? (errors
|
568
|
+
return (defined? errors) ? (errors.merge!({run_time:e})) : {run_time:e}
|
331
569
|
end
|
332
570
|
end
|
333
571
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mass_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Hanna
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -38,7 +38,8 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description:
|
41
|
+
description: A Ruby on Rails library to help with mass database operations like insert,
|
42
|
+
update, save, validations, etc (much faster than typical ActiveRecord Interactions
|
42
43
|
email:
|
43
44
|
- jnathanhdev@gmail.com
|
44
45
|
executables: []
|
@@ -117,7 +118,8 @@ rubyforge_project:
|
|
117
118
|
rubygems_version: 2.4.2
|
118
119
|
signing_key:
|
119
120
|
specification_version: 4
|
120
|
-
summary:
|
121
|
+
summary: A Ruby on Rails library to help with mass database operations like insert,
|
122
|
+
update, save, validations, etc (much faster than typical ActiveRecord Interactions...
|
121
123
|
test_files:
|
122
124
|
- test/dummy/app/assets/javascripts/application.js
|
123
125
|
- test/dummy/app/assets/stylesheets/application.css
|