upsert 2.9.10-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.ruby-version +1 -0
- data/.standard.yml +1 -0
- data/.travis.yml +63 -0
- data/.yardopts +2 -0
- data/CHANGELOG +265 -0
- data/Gemfile +20 -0
- data/LICENSE +24 -0
- data/README.md +411 -0
- data/Rakefile +54 -0
- data/lib/upsert.rb +284 -0
- data/lib/upsert/active_record_upsert.rb +12 -0
- data/lib/upsert/binary.rb +8 -0
- data/lib/upsert/column_definition.rb +79 -0
- data/lib/upsert/column_definition/mysql.rb +24 -0
- data/lib/upsert/column_definition/postgresql.rb +66 -0
- data/lib/upsert/column_definition/sqlite3.rb +34 -0
- data/lib/upsert/connection.rb +37 -0
- data/lib/upsert/connection/Java_ComMysqlJdbc_JDBC4Connection.rb +31 -0
- data/lib/upsert/connection/Java_OrgPostgresqlJdbc_PgConnection.rb +33 -0
- data/lib/upsert/connection/Java_OrgSqlite_Conn.rb +17 -0
- data/lib/upsert/connection/Mysql2_Client.rb +76 -0
- data/lib/upsert/connection/PG_Connection.rb +35 -0
- data/lib/upsert/connection/SQLite3_Database.rb +28 -0
- data/lib/upsert/connection/jdbc.rb +105 -0
- data/lib/upsert/connection/postgresql.rb +24 -0
- data/lib/upsert/connection/sqlite3.rb +19 -0
- data/lib/upsert/merge_function.rb +73 -0
- data/lib/upsert/merge_function/Java_ComMysqlJdbc_JDBC4Connection.rb +42 -0
- data/lib/upsert/merge_function/Java_OrgPostgresqlJdbc_PgConnection.rb +27 -0
- data/lib/upsert/merge_function/Java_OrgSqlite_Conn.rb +10 -0
- data/lib/upsert/merge_function/Mysql2_Client.rb +36 -0
- data/lib/upsert/merge_function/PG_Connection.rb +26 -0
- data/lib/upsert/merge_function/SQLite3_Database.rb +10 -0
- data/lib/upsert/merge_function/mysql.rb +66 -0
- data/lib/upsert/merge_function/postgresql.rb +365 -0
- data/lib/upsert/merge_function/sqlite3.rb +43 -0
- data/lib/upsert/row.rb +59 -0
- data/lib/upsert/version.rb +3 -0
- data/spec/active_record_upsert_spec.rb +26 -0
- data/spec/binary_spec.rb +21 -0
- data/spec/correctness_spec.rb +190 -0
- data/spec/database_functions_spec.rb +106 -0
- data/spec/database_spec.rb +121 -0
- data/spec/hstore_spec.rb +249 -0
- data/spec/jruby_spec.rb +9 -0
- data/spec/logger_spec.rb +52 -0
- data/spec/misc/get_postgres_reserved_words.rb +12 -0
- data/spec/misc/mysql_reserved.txt +226 -0
- data/spec/misc/pg_reserved.txt +742 -0
- data/spec/multibyte_spec.rb +27 -0
- data/spec/postgresql_spec.rb +94 -0
- data/spec/precision_spec.rb +11 -0
- data/spec/reserved_words_spec.rb +50 -0
- data/spec/sequel_spec.rb +57 -0
- data/spec/spec_helper.rb +417 -0
- data/spec/speed_spec.rb +44 -0
- data/spec/threaded_spec.rb +57 -0
- data/spec/timezones_spec.rb +58 -0
- data/spec/type_safety_spec.rb +12 -0
- data/travis/install_postgres.sh +18 -0
- data/travis/run_docker_db.sh +20 -0
- data/travis/tune_mysql.sh +7 -0
- data/upsert-java.gemspec +14 -0
- data/upsert.gemspec +13 -0
- data/upsert.gemspec.common +106 -0
- metadata +373 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
class Upsert
|
2
|
+
class MergeFunction
|
3
|
+
# @private
|
4
|
+
module Sqlite3
|
5
|
+
def self.included(klass)
|
6
|
+
klass.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def clear(*)
|
11
|
+
# not necessary
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :quoted_setter_names
|
16
|
+
attr_reader :quoted_update_names
|
17
|
+
attr_reader :quoted_selector_names
|
18
|
+
|
19
|
+
def initialize(*)
|
20
|
+
super
|
21
|
+
@quoted_setter_names = setter_keys.map { |k| connection.quote_ident k }
|
22
|
+
@quoted_update_names = setter_keys.select { |k| k !~ CREATED_COL_REGEX }.map { |k| connection.quote_ident k }
|
23
|
+
@quoted_selector_names = selector_keys.map { |k| connection.quote_ident k }
|
24
|
+
end
|
25
|
+
|
26
|
+
def create!
|
27
|
+
# not necessary
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute(row)
|
31
|
+
bind_setter_values = row.setter.values.map { |v| connection.bind_value v }
|
32
|
+
bind_selector_values = row.selector.values.map { |v| connection.bind_value v }
|
33
|
+
bind_update_values = row.setter.select{ |k,v| k !~ CREATED_COL_REGEX }.map { |k,v| connection.bind_value v }
|
34
|
+
|
35
|
+
insert_or_ignore_sql = %{INSERT OR IGNORE INTO #{quoted_table_name} (#{quoted_setter_names.join(',')}) VALUES (#{Array.new(bind_setter_values.length, '?').join(',')})}
|
36
|
+
connection.execute insert_or_ignore_sql, bind_setter_values
|
37
|
+
|
38
|
+
update_sql = %{UPDATE #{quoted_table_name} SET #{quoted_update_names.map { |qk| "#{qk}=?" }.join(',')} WHERE #{quoted_selector_names.map { |qk| "#{qk}=?" }.join(' AND ')}}
|
39
|
+
connection.execute update_sql, (bind_update_values + bind_selector_values)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/upsert/row.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
class Upsert
|
2
|
+
# @private
|
3
|
+
class Row
|
4
|
+
if RUBY_VERSION >= '1.9'
|
5
|
+
OrderedHash = ::Hash
|
6
|
+
else
|
7
|
+
begin
|
8
|
+
require 'orderedhash'
|
9
|
+
rescue LoadError
|
10
|
+
raise LoadError, "[upsert] If you're using upsert on Ruby 1.8, you need to add 'orderedhash' to your Gemfile."
|
11
|
+
end
|
12
|
+
OrderedHash = ::OrderedHash
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :selector
|
16
|
+
attr_reader :setter
|
17
|
+
attr_reader :hstore_delete_keys
|
18
|
+
|
19
|
+
def initialize(raw_selector, raw_setter, options)
|
20
|
+
eager_nullify = (options.nil? || options.fetch(:eager_nullify, true))
|
21
|
+
|
22
|
+
@selector = raw_selector.inject({}) do |memo, (k, v)|
|
23
|
+
memo[k.to_s] = v
|
24
|
+
memo
|
25
|
+
end
|
26
|
+
|
27
|
+
@hstore_delete_keys = {}
|
28
|
+
@setter = raw_setter.inject({}) do |memo, (k, v)|
|
29
|
+
k = k.to_s
|
30
|
+
if v.is_a?(::Hash) and eager_nullify
|
31
|
+
v.each do |kk, vv|
|
32
|
+
if vv.nil?
|
33
|
+
(@hstore_delete_keys[k] ||= []) << kk
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
memo[k] = v
|
38
|
+
memo
|
39
|
+
end
|
40
|
+
|
41
|
+
(selector.keys - setter.keys).each do |missing|
|
42
|
+
setter[missing] = selector[missing]
|
43
|
+
end
|
44
|
+
|
45
|
+
# there is probably a more clever way to incrementally sort these hashes
|
46
|
+
@selector = sort_hash selector
|
47
|
+
@setter = sort_hash setter
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def sort_hash(original)
|
53
|
+
original.keys.sort.inject(OrderedHash.new) do |memo, k|
|
54
|
+
memo[k] = original[k]
|
55
|
+
memo
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'upsert/active_record_upsert'
|
4
|
+
|
5
|
+
describe Upsert do
|
6
|
+
describe 'the optional active_record extension' do
|
7
|
+
describe :upsert do
|
8
|
+
it "is easy to use" do
|
9
|
+
assert_creates(Pet,[{:name => 'Jerry', :good => true}]) do
|
10
|
+
Pet.upsert({:name => 'Jerry'}, :good => false)
|
11
|
+
Pet.upsert({:name => 'Jerry'}, :good => true)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "doesn't fail inside a transaction" do
|
16
|
+
Upsert.clear_database_functions(Pet.connection)
|
17
|
+
expect {
|
18
|
+
Pet.transaction do
|
19
|
+
Pet.upsert({name: 'Simba'}, good: true)
|
20
|
+
end
|
21
|
+
}.to_not raise_error
|
22
|
+
expect(Pet.first.name).to eq('Simba')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/binary_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Upsert do
|
3
|
+
describe "supports binary upserts" do
|
4
|
+
before do
|
5
|
+
@fakes = []
|
6
|
+
10.times do
|
7
|
+
@fakes << [Faker::Name.name, Faker::Lorem.paragraphs(10).join("\n\n")]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
it "saves binary one by one" do
|
11
|
+
@fakes.each do |name, biography|
|
12
|
+
zipped_biography = Zlib::Deflate.deflate biography
|
13
|
+
upsert = Upsert.new $conn, :pets
|
14
|
+
assert_creates(Pet, [{:name => name, :zipped_biography => zipped_biography}]) do
|
15
|
+
upsert.row({:name => name}, {:zipped_biography => Upsert.binary(zipped_biography)})
|
16
|
+
end
|
17
|
+
Zlib::Inflate.inflate(Pet.find_by_name(name).zipped_biography).should == biography
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
describe Upsert do
|
5
|
+
describe 'clever correctness' do
|
6
|
+
it "doesn't confuse selector and setter" do
|
7
|
+
p = Pet.new
|
8
|
+
p.name = 'Jerry'
|
9
|
+
p.tag_number = 5
|
10
|
+
p.save!
|
11
|
+
|
12
|
+
# won't change anything because selector is wrong
|
13
|
+
u = Upsert.new($conn, :pets)
|
14
|
+
selector = {:name => 'Jerry', :tag_number => 6}
|
15
|
+
u.row(selector)
|
16
|
+
p.reload.tag_number.should == 5
|
17
|
+
next
|
18
|
+
|
19
|
+
# won't change anything because selector is wrong
|
20
|
+
u = Upsert.new($conn, :pets)
|
21
|
+
selector = {:name => 'Jerry', :tag_number => 10}
|
22
|
+
setter = { :tag_number => 5 }
|
23
|
+
u.row(selector, setter)
|
24
|
+
Pet.find_by_name('Jerry').tag_number.should == 5
|
25
|
+
|
26
|
+
u = Upsert.new($conn, :pets)
|
27
|
+
selector = { :name => 'Jerry' }
|
28
|
+
setter = { :tag_number => 10 }
|
29
|
+
u.row(selector, setter)
|
30
|
+
Pet.find_by_name('Jerry').tag_number.should == 10
|
31
|
+
|
32
|
+
u = Upsert.new($conn, :pets)
|
33
|
+
selector = { :name => 'Jerry', :tag_number => 10 }
|
34
|
+
setter = { :tag_number => 20 }
|
35
|
+
u.row(selector, setter)
|
36
|
+
Pet.find_by_name('Jerry').tag_number.should == 20
|
37
|
+
end
|
38
|
+
|
39
|
+
it "really limits its effects to the selector" do
|
40
|
+
p = Pet.new
|
41
|
+
p.name = 'Jerry'
|
42
|
+
p.gender = 'blue'
|
43
|
+
p.tag_number = 777
|
44
|
+
p.save!
|
45
|
+
Pet.find_by_name_and_gender('Jerry', 'blue').tag_number.should == 777
|
46
|
+
u = Upsert.new($conn, :pets)
|
47
|
+
selector = {:name => 'Jerry', :gender => 'red'} # this shouldn't select anything
|
48
|
+
setter = {:tag_number => 888}
|
49
|
+
u.row(selector, setter)
|
50
|
+
Pet.find_by_name_and_gender('Jerry', 'blue').tag_number.should == 777
|
51
|
+
end
|
52
|
+
|
53
|
+
# https://github.com/seamusabshere/upsert/issues/18
|
54
|
+
it "uses nil selectors" do
|
55
|
+
Pet.count.should == 0
|
56
|
+
now = Date.today
|
57
|
+
u = Upsert.new($conn, :pets)
|
58
|
+
5.times do
|
59
|
+
u.row(:gender => nil, :birthday => now)
|
60
|
+
end
|
61
|
+
|
62
|
+
Pet.count.should == 1
|
63
|
+
end
|
64
|
+
|
65
|
+
it "uses nil selectors on columns with date type" do
|
66
|
+
Pet.count.should == 0
|
67
|
+
u = Upsert.new($conn, :pets)
|
68
|
+
5.times do
|
69
|
+
u.row(:birthday => nil)
|
70
|
+
end
|
71
|
+
|
72
|
+
Pet.count.should == 1
|
73
|
+
end
|
74
|
+
|
75
|
+
it "uses nil selectors (another way of checking)" do
|
76
|
+
u = Upsert.new($conn, :pets)
|
77
|
+
now = Date.today
|
78
|
+
assert_creates(Pet, [{:name => 'Jerry', :gender => nil, :spiel => 'beagle', :birthday => now}]) do
|
79
|
+
u.row(:name => "Jerry", :gender => nil, :spiel => "samoyed")
|
80
|
+
u.row({:name => 'Jerry', :gender => nil}, :spiel => 'beagle', :birthday => now)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "works with utf-8 data" do
|
85
|
+
u = Upsert.new($conn, :pets)
|
86
|
+
records = [
|
87
|
+
{:name => '你好', :home_address => '人'},
|
88
|
+
{:name => 'Здравствуйте', :home_address => 'человек'},
|
89
|
+
{:name => '😀', :home_address => '😂'},
|
90
|
+
]
|
91
|
+
assert_creates(Pet, records) do
|
92
|
+
records.each { |rec| u.row(rec) }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it "tells you if you request a column that doesn't exist" do
|
97
|
+
u = Upsert.new($conn, :pets)
|
98
|
+
lambda { u.row(:gibberish => 'ba') }.should raise_error(/invalid col/i)
|
99
|
+
lambda { u.row(:name => 'Jerry', :gibberish => 'ba') }.should raise_error(/invalid col/i)
|
100
|
+
lambda { u.row(:name => 'Jerry', :gibberish => 'ba') }.should raise_error(/invalid col/i)
|
101
|
+
lambda { u.row(:name => 'Jerry', :gibberish => 'ba', :gender => 'male') }.should raise_error(/invalid col/i)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "works with a long setter hash" do
|
105
|
+
Upsert.batch($conn, :alphabets) do |batch|
|
106
|
+
10_000.times do |time|
|
107
|
+
setter = Hash[("a".."z").map { |letter| ["the_letter_#{letter}".to_sym, rand(100)] }]
|
108
|
+
selector = Hash[("a".."z").map { |letter| ["the_letter_#{letter}".to_sym, rand(100)] }]
|
109
|
+
batch.row(setter, selector)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "is just as correct as other ways" do
|
116
|
+
describe 'compared to native ActiveRecord' do
|
117
|
+
it "is as correct as than new/set/save" do
|
118
|
+
assert_same_result lotsa_records do |records|
|
119
|
+
records.each do |selector, setter|
|
120
|
+
if (pet = Pet.where(selector).first)
|
121
|
+
pet.update_attributes(setter)
|
122
|
+
else
|
123
|
+
pet = Pet.new
|
124
|
+
selector.each do |k, v|
|
125
|
+
pet.send "#{k}=", v
|
126
|
+
end
|
127
|
+
setter.each do |k, v|
|
128
|
+
pet.send "#{k}=", v
|
129
|
+
end
|
130
|
+
pet.save!
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
# it "is as correct as than find_or_create + update_attributes" do
|
136
|
+
# assert_same_result lotsa_records do |records|
|
137
|
+
# dynamic_method = nil
|
138
|
+
# records.each do |selector, setter|
|
139
|
+
# dynamic_method ||= "find_or_create_by_#{selector.keys.join('_or_')}"
|
140
|
+
# pet = Pet.send(dynamic_method, *selector.values)
|
141
|
+
# pet.update_attributes setter, :without_protection => true
|
142
|
+
# end
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
# it "is as correct as than create + rescue/find/update" do
|
146
|
+
# assert_same_result lotsa_records do |records|
|
147
|
+
# dynamic_method = nil
|
148
|
+
# records.each do |selector, setter|
|
149
|
+
# dynamic_method ||= "find_or_create_by_#{selector.keys.join('_or_')}"
|
150
|
+
# begin
|
151
|
+
# Pet.create selector.merge(setter), :without_protection => true
|
152
|
+
# rescue
|
153
|
+
# pet = Pet.send(dynamic_method, *selector.values)
|
154
|
+
# pet.update_attributes setter, :without_protection => true
|
155
|
+
# end
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
# end
|
159
|
+
end
|
160
|
+
|
161
|
+
if ENV['DB'] == 'mysql' || (UNIQUE_CONSTRAINT && ENV["DB"] == "postgresql")
|
162
|
+
describe 'compared to activerecord-import' do
|
163
|
+
it "is as correct as faking upserts with activerecord-import" do
|
164
|
+
assert_same_result lotsa_records do |records|
|
165
|
+
columns = nil
|
166
|
+
all_values = []
|
167
|
+
# Reverse because we want to mimic an 'overwrite' of previous values
|
168
|
+
records = records.reverse.uniq { |s, _| s } if ENV['DB'] == "postgresql"
|
169
|
+
|
170
|
+
records.each do |selector, setter|
|
171
|
+
columns ||= (selector.keys + setter.keys).uniq
|
172
|
+
all_values << columns.map do |k|
|
173
|
+
if setter.has_key?(k)
|
174
|
+
# prefer the setter so that you can change rows
|
175
|
+
setter[k]
|
176
|
+
else
|
177
|
+
selector[k]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
conflict_update = ENV['DB'] == "postgresql" ? {conflict_target: records.first.first.keys, columns: columns} : columns
|
183
|
+
Pet.import columns, all_values, :timestamps => false, :on_duplicate_key_update => conflict_update
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'stringio'
|
3
|
+
require 'upsert/merge_function/postgresql'
|
4
|
+
|
5
|
+
describe Upsert do
|
6
|
+
describe 'database functions' do
|
7
|
+
version = 'postgresql' == ENV['DB'] ? Upsert::MergeFunction::Postgresql.extract_version(
|
8
|
+
Pet.connection.select_value("SHOW server_version")
|
9
|
+
) : 0
|
10
|
+
before(:each) {
|
11
|
+
skip "Not using DB functions" if 'postgresql' == ENV['DB'] && UNIQUE_CONSTRAINT && version >= 90500
|
12
|
+
}
|
13
|
+
it "does not re-use merge functions across connections" do
|
14
|
+
begin
|
15
|
+
io = StringIO.new
|
16
|
+
old_logger = Upsert.logger
|
17
|
+
Upsert.logger = Logger.new io, Logger::INFO
|
18
|
+
|
19
|
+
# clear, create (#1)
|
20
|
+
Upsert.clear_database_functions($conn_factory.new_connection)
|
21
|
+
Upsert.new($conn_factory.new_connection, :pets).row :name => 'hello'
|
22
|
+
|
23
|
+
# clear, create (#2)
|
24
|
+
Upsert.clear_database_functions($conn_factory.new_connection)
|
25
|
+
Upsert.new($conn_factory.new_connection, :pets).row :name => 'hello'
|
26
|
+
|
27
|
+
io.rewind
|
28
|
+
hits = io.read.split("\n").grep(/Creating or replacing/)
|
29
|
+
hits.length.should == 2
|
30
|
+
ensure
|
31
|
+
Upsert.logger = old_logger
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "does not re-use merge functions even when on the same connection" do
|
36
|
+
begin
|
37
|
+
io = StringIO.new
|
38
|
+
old_logger = Upsert.logger
|
39
|
+
Upsert.logger = Logger.new io, Logger::INFO
|
40
|
+
|
41
|
+
connection = $conn_factory.new_connection
|
42
|
+
|
43
|
+
# clear, create (#1)
|
44
|
+
Upsert.clear_database_functions(connection)
|
45
|
+
Upsert.new(connection, :pets).row :name => 'hello'
|
46
|
+
|
47
|
+
# clear, create (#2)
|
48
|
+
Upsert.clear_database_functions(connection)
|
49
|
+
Upsert.new(connection, :pets).row :name => 'hello'
|
50
|
+
|
51
|
+
io.rewind
|
52
|
+
hits = io.read.split("\n").grep(/Creating or replacing/)
|
53
|
+
hits.length.should == 2
|
54
|
+
ensure
|
55
|
+
Upsert.logger = old_logger
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "re-uses merge functions within batch" do
|
60
|
+
begin
|
61
|
+
io = StringIO.new
|
62
|
+
old_logger = Upsert.logger
|
63
|
+
Upsert.logger = Logger.new io, Logger::INFO
|
64
|
+
|
65
|
+
# clear
|
66
|
+
Upsert.clear_database_functions($conn_factory.new_connection)
|
67
|
+
|
68
|
+
# create
|
69
|
+
Upsert.batch($conn_factory.new_connection, :pets) do |upsert|
|
70
|
+
upsert.row :name => 'hello'
|
71
|
+
upsert.row :name => 'world'
|
72
|
+
end
|
73
|
+
|
74
|
+
io.rewind
|
75
|
+
hits = io.read.split("\n").grep(/Creating or replacing/)
|
76
|
+
hits.length.should == 1
|
77
|
+
ensure
|
78
|
+
Upsert.logger = old_logger
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "assumes function exists if told to" do
|
83
|
+
begin
|
84
|
+
io = StringIO.new
|
85
|
+
old_logger = Upsert.logger
|
86
|
+
Upsert.logger = Logger.new io, Logger::INFO
|
87
|
+
|
88
|
+
# clear
|
89
|
+
Upsert.clear_database_functions($conn_factory.new_connection)
|
90
|
+
|
91
|
+
# tries, "went missing", creates
|
92
|
+
Upsert.new($conn_factory.new_connection, :pets, :assume_function_exists => true).row :name => 'hello'
|
93
|
+
|
94
|
+
# just works
|
95
|
+
Upsert.new($conn_factory.new_connection, :pets, :assume_function_exists => true).row :name => 'hello'
|
96
|
+
|
97
|
+
io.rewind
|
98
|
+
lines = io.read.split("\n")
|
99
|
+
lines.grep(/went missing/).length.should == 1
|
100
|
+
lines.grep(/Creating or replacing/).length.should == 1
|
101
|
+
ensure
|
102
|
+
Upsert.logger = old_logger
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end if %w{ postgresql mysql }.include?(ENV['DB'])
|