Skip to content

Commit 6df13eb

Browse files
committed
Implemented ignore parameter for PostgreSQL connection
1 parent 89e56b4 commit 6df13eb

File tree

2 files changed

+82
-26
lines changed

2 files changed

+82
-26
lines changed

lib/bulk_insert/worker.rb

+43-25
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ class Worker
33
attr_reader :connection
44
attr_accessor :set_size
55
attr_accessor :after_save_callback
6+
attr_accessor :adapter_name
7+
attr_reader :ignore
68

79
def initialize(connection, table_name, column_names, set_size=500, ignore=false)
810
@connection = connection
911
@set_size = set_size
1012

11-
@adapter_name = @connection.adapter_name
13+
@adapter_name = connection.adapter_name
1214
# INSERT IGNORE only fails inserts with duplicate keys or unallowed nulls not the whole set of inserts
13-
@ignore = ignore ? "IGNORE" : nil
15+
@ignore = ignore
1416

1517
columns = connection.columns(table_name)
1618
column_map = columns.inject({}) { |h, c| h.update(c.name => c) }
@@ -66,34 +68,50 @@ def after_save(&block)
6668

6769
def save!
6870
if pending?
69-
sql = "INSERT #{@ignore} INTO #{@table_name} (#{@column_names}) VALUES "
70-
@now = Time.now
71-
72-
rows = []
73-
@set.each do |row|
74-
values = []
75-
@columns.zip(row) do |column, value|
76-
value = @now if value == :__timestamp_placeholder
77-
78-
if ActiveRecord::VERSION::STRING >= "5.0.0"
79-
value = @connection.type_cast_from_column(column, value) if column
80-
values << @connection.quote(value)
81-
else
82-
values << @connection.quote(value, column)
83-
end
84-
end
85-
rows << "(#{values.join(',')})"
86-
end
87-
88-
sql << rows.join(",")
89-
@connection.execute(sql)
90-
71+
@connection.execute(compose_insert_query)
9172
@after_save_callback.() if @after_save_callback
92-
9373
@set.clear
9474
end
9575

9676
self
9777
end
78+
79+
private
80+
81+
def compose_insert_query
82+
sql = insert_sql_statement
83+
@now = Time.now
84+
85+
rows = []
86+
@set.each do |row|
87+
values = []
88+
@columns.zip(row) do |column, value|
89+
value = @now if value == :__timestamp_placeholder
90+
91+
if ActiveRecord::VERSION::STRING >= "5.0.0"
92+
value = @connection.type_cast_from_column(column, value) if column
93+
values << @connection.quote(value)
94+
else
95+
values << @connection.quote(value, column)
96+
end
97+
end
98+
rows << "(#{values.join(',')})"
99+
end
100+
101+
sql << rows.join(",")
102+
sql << on_conflict_statement
103+
sql
104+
end
105+
106+
def insert_sql_statement
107+
ignore = nil
108+
ignore = 'IGNORE' if (adapter_name == 'MySQL') && @ignore
109+
"INSERT #{ignore} INTO #{@table_name} (#{@column_names}) VALUES "
110+
end
111+
112+
def on_conflict_statement
113+
return ' ON CONFLICT DO NOTHING' if (adapter_name == 'PostgreSQL') && @ignore
114+
''
115+
end
98116
end
99117
end

test/bulk_insert/worker_test.rb

+39-1
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,43 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
150150

151151
assert_equal "hello", @insert.after_save_callback.()
152152
end
153-
end
154153

154+
test "adapter dependent default methods" do
155+
assert_equal @insert.adapter_name, 'SQLite'
156+
assert_equal @insert.send(:insert_sql_statement), "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES "
157+
assert_equal @insert.send(:compose_insert_query), "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES "
158+
end
159+
160+
test "adapter dependent mysql methods" do
161+
mysql_worker = BulkInsert::Worker.new(
162+
Testing.connection,
163+
Testing.table_name,
164+
%w(greeting age happy created_at updated_at color),
165+
500, # batch size
166+
true) # ignore
167+
mysql_worker.adapter_name = 'MySQL'
168+
169+
assert_equal mysql_worker.adapter_name, 'MySQL'
170+
assert_equal (mysql_worker.adapter_name == 'MySQL'), true
171+
assert_equal mysql_worker.ignore, true
172+
assert_equal ((mysql_worker.adapter_name == 'MySQL') & mysql_worker.ignore), true
173+
174+
mysql_worker.add ["Yo", 15, false, nil, nil]
175+
176+
assert_equal mysql_worker.send(:compose_insert_query), "INSERT IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,'f',NULL,NULL,'chartreuse')"
177+
end
178+
179+
test "adapter dependent postgresql methods" do
180+
pgsql_worker = BulkInsert::Worker.new(
181+
Testing.connection,
182+
Testing.table_name,
183+
%w(greeting age happy created_at updated_at color),
184+
500, # batch size
185+
true) # ignore
186+
pgsql_worker.adapter_name = 'PostgreSQL'
187+
pgsql_worker.add ["Yo", 15, false, nil, nil]
188+
189+
assert_equal pgsql_worker.send(: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"
190+
191+
end
192+
end

0 commit comments

Comments
 (0)