bulk_insert 1.8.2 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -0
- data/lib/bulk_insert/version.rb +2 -2
- data/lib/bulk_insert/worker.rb +13 -2
- data/test/bulk_insert/worker_test.rb +115 -57
- data/test/bulk_insert_test.rb +10 -2
- data/test/connection_mocks.rb +140 -0
- data/test/dummy/app/assets/config/manifest.js +0 -0
- data/test/dummy/config/application.rb +44 -1
- data/test/dummy/config/database.yml +15 -19
- data/test/dummy/config/environments/test.rb +1 -1
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +20749 -0
- metadata +7 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 385a28475e8a07cdf1cad85aacf241734ce65ed922648417c7beda2b88a5b3c9
|
4
|
+
data.tar.gz: a14a05da23f256f3d30cf69fab032ec72c5953fe1ddb3ccc45a0673bef717266
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbe45a91a166d6faa3e2899a4fad7ac1af8a6e050249adbc810121ddc3000f0786c277b8c240809935bbb80178bbb1df43044dda32a02cea87c0d5d956e3cee1
|
7
|
+
data.tar.gz: 165de20f26c00dfcbe605866576f731199f692b7bccb07e671b8dcb9541552e39d0940a9f6fff73701286586f909e7be1254be6df157f41f76e83b105e88b9f2
|
data/README.md
CHANGED
@@ -191,6 +191,30 @@ end
|
|
191
191
|
worker.result_sets
|
192
192
|
```
|
193
193
|
|
194
|
+
## Ruby and Rails Versions Supported
|
195
|
+
|
196
|
+
> :warning: The scope of this gem may be somehow covered natively by the `.insert_all` API
|
197
|
+
> introduced by [Rails 6](https://apidock.com/rails/v6.0.0/ActiveRecord/Persistence/ClassMethods/insert_all).
|
198
|
+
> This gem represents the state of art for rails version < 6 and it is still open to
|
199
|
+
> further developments for more recent versions.
|
200
|
+
|
201
|
+
The current CI prevents regressions on the following versions:
|
202
|
+
|
203
|
+
ruby / rails | `~>3` | `~>4` | `~>5` | `~>6`
|
204
|
+
:-----------:|-------|-------|-------|------
|
205
|
+
2.2 | yes | yes | no | no
|
206
|
+
2.3 | yes | yes | yes | no
|
207
|
+
2.4 | no | yes | yes | no
|
208
|
+
2.5 | no | no | yes | yes
|
209
|
+
2.6 | no | no | yes | yes
|
210
|
+
2.7 | no | no | yes | yes
|
211
|
+
|
212
|
+
The adapters covered in the CI are:
|
213
|
+
* sqlite
|
214
|
+
* mysql
|
215
|
+
* postgresql
|
216
|
+
|
217
|
+
|
194
218
|
## License
|
195
219
|
|
196
220
|
BulkInsert is released under the MIT license (see MIT-LICENSE) by
|
data/lib/bulk_insert/version.rb
CHANGED
data/lib/bulk_insert/worker.rb
CHANGED
@@ -93,8 +93,19 @@ module BulkInsert
|
|
93
93
|
|
94
94
|
def execute_query
|
95
95
|
if query = compose_insert_query
|
96
|
-
|
97
|
-
|
96
|
+
|
97
|
+
# Return primary key support broke mysql compatibility
|
98
|
+
# with rails < 5 mysql adapter. (see issue #41)
|
99
|
+
if ActiveRecord::VERSION::STRING < "5.0.0" && @statement_adapter.is_a?(StatementAdapters::MySQLAdapter)
|
100
|
+
# raise an exception for unsupported return_primary_keys
|
101
|
+
raise ArgumentError.new("BulkInsert does not support @return_primary_keys for mysql and rails < 5") if @return_primary_keys
|
102
|
+
|
103
|
+
# restore v1.6 query execution
|
104
|
+
@connection.execute(query)
|
105
|
+
else
|
106
|
+
result_set = @connection.exec_query(query)
|
107
|
+
@result_sets.push(result_set) if @return_primary_keys
|
108
|
+
end
|
98
109
|
end
|
99
110
|
end
|
100
111
|
|
@@ -1,14 +1,17 @@
|
|
1
1
|
require 'minitest/mock'
|
2
2
|
require 'test_helper'
|
3
|
+
require 'connection_mocks'
|
3
4
|
|
4
5
|
class BulkInsertWorkerTest < ActiveSupport::TestCase
|
6
|
+
include ConnectionMocks
|
7
|
+
|
5
8
|
setup do
|
6
9
|
@insert = BulkInsert::Worker.new(
|
7
10
|
Testing.connection,
|
8
11
|
Testing.table_name,
|
9
12
|
'id',
|
10
13
|
%w(greeting age happy created_at updated_at color))
|
11
|
-
@now = Time.now
|
14
|
+
@now = Time.now.utc
|
12
15
|
end
|
13
16
|
|
14
17
|
test "empty insert is not pending" do
|
@@ -37,8 +40,8 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
37
40
|
@insert.save!
|
38
41
|
|
39
42
|
record = Testing.first
|
40
|
-
assert_operator record.created_at, :>=, now
|
41
|
-
assert_operator record.updated_at, :>=, now
|
43
|
+
assert_operator record.created_at.to_i, :>=, now.to_i
|
44
|
+
assert_operator record.updated_at.to_i, :>=, now.to_i
|
42
45
|
end
|
43
46
|
|
44
47
|
test "default timestamp columns should be equivalent for the entire batch" do
|
@@ -111,8 +114,8 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
111
114
|
@insert.add ["Hello", 25, true, @now, @now]
|
112
115
|
@insert.save!
|
113
116
|
|
114
|
-
yo = Testing.
|
115
|
-
hello = Testing.
|
117
|
+
yo = Testing.where(greeting: 'Yo').first
|
118
|
+
hello = Testing.where(greeting: 'Hello').first
|
116
119
|
|
117
120
|
assert_not_nil yo
|
118
121
|
assert_equal 15, yo.age
|
@@ -144,6 +147,10 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
144
147
|
true
|
145
148
|
)
|
146
149
|
|
150
|
+
# return_primary_keys is not supported for mysql and rails < 5
|
151
|
+
# skip is not supported in the minitest version used for testing rails 3
|
152
|
+
return if ActiveRecord::VERSION::STRING < "5.0.0" && worker.adapter_name =~ /^mysql/i
|
153
|
+
|
147
154
|
assert_no_difference -> { worker.result_sets.count } do
|
148
155
|
worker.save!
|
149
156
|
end
|
@@ -239,8 +246,8 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
239
246
|
@insert.add ["Hello", 25, true, @now, @now]
|
240
247
|
@insert.save!
|
241
248
|
|
242
|
-
yo = Testing.
|
243
|
-
hello = Testing.
|
249
|
+
yo = Testing.where(greeting: 'Yo').first
|
250
|
+
hello = Testing.where(greeting: 'Hello').first
|
244
251
|
|
245
252
|
assert_nil yo
|
246
253
|
assert_not_nil hello
|
@@ -255,24 +262,35 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
255
262
|
@insert.add ["Hello", 25, true, @now, @now]
|
256
263
|
@insert.save!
|
257
264
|
|
258
|
-
yo = Testing.
|
259
|
-
hello = Testing.
|
265
|
+
yo = Testing.where(greeting: 'Yo').first
|
266
|
+
hello = Testing.where(greeting: 'Hello').first
|
260
267
|
|
261
268
|
assert_nil yo
|
262
269
|
assert_nil hello
|
263
270
|
end
|
264
271
|
|
265
|
-
test "adapter dependent
|
266
|
-
|
267
|
-
|
272
|
+
test "adapter dependent SQLite methods" do
|
273
|
+
connection = Testing.connection
|
274
|
+
stub_connection_if_needed(connection, 'SQLite') do
|
275
|
+
sqlite_worker = BulkInsert::Worker.new(
|
276
|
+
connection,
|
277
|
+
Testing.table_name,
|
278
|
+
'id',
|
279
|
+
%w(greeting age happy created_at updated_at color),
|
280
|
+
500 # batch size
|
281
|
+
)
|
282
|
+
|
283
|
+
assert_equal sqlite_worker.adapter_name, 'SQLite'
|
284
|
+
assert_equal sqlite_worker.insert_sql_statement, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES "
|
268
285
|
|
269
|
-
|
270
|
-
|
286
|
+
sqlite_worker.add ["Yo", 15, false, nil, nil]
|
287
|
+
assert_equal sqlite_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
|
288
|
+
end
|
271
289
|
end
|
272
290
|
|
273
|
-
test "adapter dependent
|
291
|
+
test "adapter dependent MySQL methods" do
|
274
292
|
connection = Testing.connection
|
275
|
-
connection
|
293
|
+
stub_connection_if_needed(connection, 'mysql') do
|
276
294
|
mysql_worker = BulkInsert::Worker.new(
|
277
295
|
connection,
|
278
296
|
Testing.table_name,
|
@@ -282,20 +300,21 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
282
300
|
true # ignore
|
283
301
|
)
|
284
302
|
|
285
|
-
assert_equal mysql_worker.adapter_name, '
|
286
|
-
assert_equal (mysql_worker.adapter_name == '
|
303
|
+
assert_equal mysql_worker.adapter_name, 'mysql'
|
304
|
+
assert_equal (mysql_worker.adapter_name == 'mysql'), true
|
287
305
|
assert_equal mysql_worker.ignore, true
|
288
|
-
assert_equal ((mysql_worker.adapter_name == '
|
306
|
+
assert_equal ((mysql_worker.adapter_name == 'mysql') & mysql_worker.ignore), true
|
289
307
|
|
290
308
|
mysql_worker.add ["Yo", 15, false, nil, nil]
|
291
309
|
|
292
|
-
|
310
|
+
assert_statement_adapter mysql_worker, 'BulkInsert::StatementAdapters::MySQLAdapter'
|
311
|
+
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse')"
|
293
312
|
end
|
294
313
|
end
|
295
314
|
|
296
315
|
test "adapter dependent mysql methods work for mysql2" do
|
297
316
|
connection = Testing.connection
|
298
|
-
connection
|
317
|
+
stub_connection_if_needed(connection, 'mysql2') do
|
299
318
|
mysql_worker = BulkInsert::Worker.new(
|
300
319
|
connection,
|
301
320
|
Testing.table_name,
|
@@ -305,18 +324,19 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
305
324
|
true, # ignore
|
306
325
|
true) # update_duplicates
|
307
326
|
|
308
|
-
assert_equal mysql_worker.adapter_name, '
|
327
|
+
assert_equal mysql_worker.adapter_name, 'mysql2'
|
309
328
|
assert mysql_worker.ignore
|
310
329
|
|
311
330
|
mysql_worker.add ["Yo", 15, false, nil, nil]
|
312
331
|
|
313
|
-
|
332
|
+
assert_statement_adapter mysql_worker, 'BulkInsert::StatementAdapters::MySQLAdapter'
|
333
|
+
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse') ON DUPLICATE KEY UPDATE `greeting`=VALUES(`greeting`), `age`=VALUES(`age`), `happy`=VALUES(`happy`), `created_at`=VALUES(`created_at`), `updated_at`=VALUES(`updated_at`), `color`=VALUES(`color`)"
|
314
334
|
end
|
315
335
|
end
|
316
336
|
|
317
337
|
test "adapter dependent Mysql2Spatial methods" do
|
318
338
|
connection = Testing.connection
|
319
|
-
connection
|
339
|
+
stub_connection_if_needed(connection, 'mysql2spatial') do
|
320
340
|
mysql_worker = BulkInsert::Worker.new(
|
321
341
|
connection,
|
322
342
|
Testing.table_name,
|
@@ -325,17 +345,18 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
325
345
|
500, # batch size
|
326
346
|
true) # ignore
|
327
347
|
|
328
|
-
assert_equal mysql_worker.adapter_name, '
|
348
|
+
assert_equal mysql_worker.adapter_name, 'mysql2spatial'
|
329
349
|
|
330
350
|
mysql_worker.add ["Yo", 15, false, nil, nil]
|
331
351
|
|
332
|
-
|
333
|
-
|
352
|
+
assert_statement_adapter mysql_worker, 'BulkInsert::StatementAdapters::MySQLAdapter'
|
353
|
+
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse')"
|
354
|
+
end
|
334
355
|
end
|
335
356
|
|
336
357
|
test "adapter dependent postgresql methods" do
|
337
358
|
connection = Testing.connection
|
338
|
-
connection
|
359
|
+
stub_connection_if_needed(connection, 'PostgreSQL') do
|
339
360
|
pgsql_worker = BulkInsert::Worker.new(
|
340
361
|
connection,
|
341
362
|
Testing.table_name,
|
@@ -349,13 +370,19 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
349
370
|
|
350
371
|
pgsql_worker.add ["Yo", 15, false, nil, nil]
|
351
372
|
|
352
|
-
|
373
|
+
assert_statement_adapter pgsql_worker, 'BulkInsert::StatementAdapters::PostgreSQLAdapter'
|
374
|
+
|
375
|
+
if ActiveRecord::VERSION::STRING >= "5.0.0"
|
376
|
+
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse') ON CONFLICT DO NOTHING RETURNING id"
|
377
|
+
else
|
378
|
+
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,'f',NULL,NULL,'chartreuse') ON CONFLICT DO NOTHING RETURNING id"
|
379
|
+
end
|
353
380
|
end
|
354
381
|
end
|
355
382
|
|
356
383
|
test "adapter dependent postgresql methods (no ignore, no update_duplicates)" do
|
357
384
|
connection = Testing.connection
|
358
|
-
connection
|
385
|
+
stub_connection_if_needed(connection, 'PostgreSQL') do
|
359
386
|
pgsql_worker = BulkInsert::Worker.new(
|
360
387
|
connection,
|
361
388
|
Testing.table_name,
|
@@ -369,13 +396,19 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
369
396
|
|
370
397
|
pgsql_worker.add ["Yo", 15, false, nil, nil]
|
371
398
|
|
372
|
-
|
399
|
+
assert_statement_adapter pgsql_worker, 'BulkInsert::StatementAdapters::PostgreSQLAdapter'
|
400
|
+
|
401
|
+
if ActiveRecord::VERSION::STRING >= "5.0.0"
|
402
|
+
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse') RETURNING id"
|
403
|
+
else
|
404
|
+
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,'f',NULL,NULL,'chartreuse') RETURNING id"
|
405
|
+
end
|
373
406
|
end
|
374
407
|
end
|
375
408
|
|
376
409
|
test "adapter dependent postgresql methods (with update_duplicates)" do
|
377
410
|
connection = Testing.connection
|
378
|
-
connection
|
411
|
+
stub_connection_if_needed(connection, 'PostgreSQL') do
|
379
412
|
pgsql_worker = BulkInsert::Worker.new(
|
380
413
|
connection,
|
381
414
|
Testing.table_name,
|
@@ -388,13 +421,19 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
388
421
|
)
|
389
422
|
pgsql_worker.add ["Yo", 15, false, nil, nil]
|
390
423
|
|
391
|
-
|
424
|
+
assert_statement_adapter pgsql_worker, 'BulkInsert::StatementAdapters::PostgreSQLAdapter'
|
425
|
+
|
426
|
+
if ActiveRecord::VERSION::STRING >= "5.0.0"
|
427
|
+
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse') ON CONFLICT(greeting, age, happy) DO UPDATE SET greeting=EXCLUDED.greeting, age=EXCLUDED.age, happy=EXCLUDED.happy, created_at=EXCLUDED.created_at, updated_at=EXCLUDED.updated_at, color=EXCLUDED.color RETURNING id"
|
428
|
+
else
|
429
|
+
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,'f',NULL,NULL,'chartreuse') ON CONFLICT(greeting, age, happy) DO UPDATE SET greeting=EXCLUDED.greeting, age=EXCLUDED.age, happy=EXCLUDED.happy, created_at=EXCLUDED.created_at, updated_at=EXCLUDED.updated_at, color=EXCLUDED.color RETURNING id"
|
430
|
+
end
|
392
431
|
end
|
393
432
|
end
|
394
433
|
|
395
434
|
test "adapter dependent PostGIS methods" do
|
396
435
|
connection = Testing.connection
|
397
|
-
connection
|
436
|
+
stub_connection_if_needed(connection, 'postgis') do
|
398
437
|
pgsql_worker = BulkInsert::Worker.new(
|
399
438
|
connection,
|
400
439
|
Testing.table_name,
|
@@ -407,41 +446,55 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
407
446
|
)
|
408
447
|
pgsql_worker.add ["Yo", 15, false, nil, nil]
|
409
448
|
|
410
|
-
|
449
|
+
assert_statement_adapter pgsql_worker, 'BulkInsert::StatementAdapters::PostgreSQLAdapter'
|
450
|
+
|
451
|
+
if ActiveRecord::VERSION::STRING >= "5.0.0"
|
452
|
+
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse') ON CONFLICT DO NOTHING RETURNING id"
|
453
|
+
else
|
454
|
+
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,'f',NULL,NULL,'chartreuse') ON CONFLICT DO NOTHING RETURNING id"
|
455
|
+
end
|
411
456
|
end
|
412
457
|
end
|
413
458
|
|
414
459
|
test "adapter dependent sqlite3 methods (with lowercase adapter name)" do
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
460
|
+
connection = Testing.connection
|
461
|
+
stub_connection_if_needed(connection, 'sqlite3') do
|
462
|
+
sqlite_worker = BulkInsert::Worker.new(
|
463
|
+
Testing.connection,
|
464
|
+
Testing.table_name,
|
465
|
+
'id',
|
466
|
+
%w(greeting age happy created_at updated_at color),
|
467
|
+
500, # batch size
|
468
|
+
true) # ignore
|
469
|
+
sqlite_worker.adapter_name = 'sqlite3'
|
470
|
+
sqlite_worker.add ["Yo", 15, false, nil, nil]
|
424
471
|
|
425
|
-
|
472
|
+
assert_statement_adapter sqlite_worker, 'BulkInsert::StatementAdapters::SQLiteAdapter'
|
473
|
+
assert_equal sqlite_worker.compose_insert_query, "INSERT OR IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
|
474
|
+
end
|
426
475
|
end
|
427
476
|
|
428
477
|
test "adapter dependent sqlite3 methods (with stylecase adapter name)" do
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
478
|
+
connection = Testing.connection
|
479
|
+
stub_connection_if_needed(connection, 'SQLite') do
|
480
|
+
sqlite_worker = BulkInsert::Worker.new(
|
481
|
+
connection,
|
482
|
+
Testing.table_name,
|
483
|
+
'id',
|
484
|
+
%w(greeting age happy created_at updated_at color),
|
485
|
+
500, # batch size
|
486
|
+
true) # ignore
|
487
|
+
sqlite_worker.adapter_name = 'SQLite'
|
488
|
+
sqlite_worker.add ["Yo", 15, false, nil, nil]
|
438
489
|
|
439
|
-
|
490
|
+
assert_statement_adapter sqlite_worker, 'BulkInsert::StatementAdapters::SQLiteAdapter'
|
491
|
+
assert_equal sqlite_worker.compose_insert_query, "INSERT OR IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
|
492
|
+
end
|
440
493
|
end
|
441
494
|
|
442
495
|
test "mysql adapter can update duplicates" do
|
443
496
|
connection = Testing.connection
|
444
|
-
connection
|
497
|
+
stub_connection_if_needed(connection, 'mysql') do
|
445
498
|
mysql_worker = BulkInsert::Worker.new(
|
446
499
|
connection,
|
447
500
|
Testing.table_name,
|
@@ -453,7 +506,12 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
|
|
453
506
|
)
|
454
507
|
mysql_worker.add ["Yo", 15, false, nil, nil]
|
455
508
|
|
456
|
-
|
509
|
+
assert_statement_adapter mysql_worker, 'BulkInsert::StatementAdapters::MySQLAdapter'
|
510
|
+
assert_equal mysql_worker.compose_insert_query, "INSERT INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse') ON DUPLICATE KEY UPDATE `greeting`=VALUES(`greeting`), `age`=VALUES(`age`), `happy`=VALUES(`happy`), `created_at`=VALUES(`created_at`), `updated_at`=VALUES(`updated_at`), `color`=VALUES(`color`)"
|
457
511
|
end
|
458
512
|
end
|
513
|
+
|
514
|
+
def assert_statement_adapter(worker, adapter_name)
|
515
|
+
assert_equal worker.instance_variable_get(:@statement_adapter).class.to_s, adapter_name
|
516
|
+
end
|
459
517
|
end
|
data/test/bulk_insert_test.rb
CHANGED
@@ -30,8 +30,16 @@ class BulkInsertTest < ActiveSupport::TestCase
|
|
30
30
|
test "with option to return primary keys, worker should have result sets" do
|
31
31
|
worker = Testing.bulk_insert(return_primary_keys: true)
|
32
32
|
worker.add greeting: "yo"
|
33
|
-
|
34
|
-
|
33
|
+
|
34
|
+
# return_primary_keys is not supported for mysql and rails < 5
|
35
|
+
# this test ensures that the case is covered in the CI and handled as expected
|
36
|
+
if ActiveRecord::VERSION::STRING < "5.0.0" && worker.adapter_name =~ /^mysql/i
|
37
|
+
error = assert_raise(ArgumentError) { worker.save! }
|
38
|
+
assert_equal error.message, "BulkInsert does not support @return_primary_keys for mysql and rails < 5"
|
39
|
+
else
|
40
|
+
worker.save!
|
41
|
+
assert_equal 1, worker.result_sets.count
|
42
|
+
end
|
35
43
|
end
|
36
44
|
|
37
45
|
test "bulk_insert with array should save the array immediately" do
|
@@ -0,0 +1,140 @@
|
|
1
|
+
module ConnectionMocks
|
2
|
+
DOUBLE_QUOTE_PROC = Proc.new do |value, *_column|
|
3
|
+
return value unless value.is_a? String
|
4
|
+
"\"#{value}\""
|
5
|
+
end
|
6
|
+
|
7
|
+
BACKTICK_QUOTE_PROC = Proc.new do |value, *_column|
|
8
|
+
return value unless value.is_a? String
|
9
|
+
'`' + value + '`'
|
10
|
+
end
|
11
|
+
|
12
|
+
BOOLEAN_VALUE_QUOTE_PROC = Proc.new do |value, *_column|
|
13
|
+
case value
|
14
|
+
when String
|
15
|
+
"'" + value + "'"
|
16
|
+
when TrueClass
|
17
|
+
'TRUE'
|
18
|
+
when FalseClass
|
19
|
+
'FALSE'
|
20
|
+
when NilClass
|
21
|
+
'NULL'
|
22
|
+
else
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
LITERAL_BOOLEAN_VALUE_QUOTE_PROC = Proc.new do |value, *_column|
|
28
|
+
case value
|
29
|
+
when String
|
30
|
+
"'" + value + "'"
|
31
|
+
when TrueClass
|
32
|
+
"'t'"
|
33
|
+
when FalseClass
|
34
|
+
"'f'"
|
35
|
+
when NilClass
|
36
|
+
'NULL'
|
37
|
+
else
|
38
|
+
value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
DEFAULT_VALUE_QUOTE_PROC = Proc.new do |value, *_column|
|
43
|
+
case value
|
44
|
+
when String
|
45
|
+
"'" + value + "'"
|
46
|
+
when TrueClass
|
47
|
+
1
|
48
|
+
when FalseClass
|
49
|
+
0
|
50
|
+
when NilClass
|
51
|
+
'NULL'
|
52
|
+
else
|
53
|
+
value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
ColumnMock = Struct.new(:name, :default)
|
58
|
+
COLUMNS_MOCK_PROC = Proc.new do |*_table_name|
|
59
|
+
%w(id greeting age happy created_at updated_at color).zip(
|
60
|
+
[nil, nil, nil, nil, nil, nil, "chartreuse"]
|
61
|
+
).map do |column_name, default|
|
62
|
+
ColumnMock.new(column_name, default)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
MockTypeSerialize = Struct.new(:column) do
|
67
|
+
def serialize(value); value; end
|
68
|
+
end
|
69
|
+
CAST_COLUMN_MOCK_PROC = Proc.new do |column|
|
70
|
+
MockTypeSerialize.new(column)
|
71
|
+
end
|
72
|
+
|
73
|
+
def stub_connection_if_needed(connection, adapter_name)
|
74
|
+
raise "You need to provide a block" unless block_given?
|
75
|
+
if connection.adapter_name == adapter_name
|
76
|
+
yield
|
77
|
+
else
|
78
|
+
common_mocks(connection, adapter_name) do
|
79
|
+
case adapter_name
|
80
|
+
when /^mysql/i
|
81
|
+
mock_mysql_connection(connection, adapter_name) do
|
82
|
+
yield
|
83
|
+
end
|
84
|
+
when /\APost(?:greSQL|GIS)/i
|
85
|
+
mock_postgresql_connection(connection, adapter_name) do
|
86
|
+
yield
|
87
|
+
end
|
88
|
+
else
|
89
|
+
connection.stub :quote_table_name, DOUBLE_QUOTE_PROC do
|
90
|
+
connection.stub :quote_column_name, DOUBLE_QUOTE_PROC do
|
91
|
+
connection.stub :quote, DEFAULT_VALUE_QUOTE_PROC do
|
92
|
+
yield
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def common_mocks(connection, adapter_name)
|
102
|
+
connection.stub :adapter_name, adapter_name do
|
103
|
+
connection.stub :columns, COLUMNS_MOCK_PROC do
|
104
|
+
if ActiveRecord::VERSION::STRING >= "5.0.0"
|
105
|
+
connection.stub :lookup_cast_type_from_column, CAST_COLUMN_MOCK_PROC do
|
106
|
+
yield
|
107
|
+
end
|
108
|
+
else
|
109
|
+
yield
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def mock_mysql_connection(connection, adapter_name)
|
116
|
+
connection.stub :quote_table_name, BACKTICK_QUOTE_PROC do
|
117
|
+
connection.stub :quote_column_name, BACKTICK_QUOTE_PROC do
|
118
|
+
connection.stub :quote, BOOLEAN_VALUE_QUOTE_PROC do
|
119
|
+
yield
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def mock_postgresql_connection(connection, adapter_name)
|
126
|
+
connection.stub :quote_table_name, DOUBLE_QUOTE_PROC do
|
127
|
+
connection.stub :quote_column_name, DOUBLE_QUOTE_PROC do
|
128
|
+
if ActiveRecord::VERSION::STRING >= "5.0.0"
|
129
|
+
connection.stub :quote, BOOLEAN_VALUE_QUOTE_PROC do
|
130
|
+
yield
|
131
|
+
end
|
132
|
+
else
|
133
|
+
connection.stub :quote, LITERAL_BOOLEAN_VALUE_QUOTE_PROC do
|
134
|
+
yield
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|