mass_record 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|