bulk_insert 1.8.2 → 1.9.0
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/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
|