upsert 0.3.4 → 0.4.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.
Files changed (51) hide show
  1. data/CHANGELOG +12 -0
  2. data/README.md +6 -9
  3. data/Rakefile +9 -14
  4. data/lib/upsert.rb +40 -71
  5. data/lib/upsert/buffer.rb +36 -0
  6. data/lib/upsert/buffer/mysql2_client.rb +67 -0
  7. data/lib/upsert/buffer/pg_connection.rb +54 -0
  8. data/lib/upsert/buffer/pg_connection/merge_function.rb +138 -0
  9. data/lib/upsert/buffer/sqlite3_database.rb +13 -0
  10. data/lib/upsert/connection.rb +41 -0
  11. data/lib/upsert/connection/mysql2_client.rb +53 -0
  12. data/lib/upsert/connection/pg_connection.rb +39 -0
  13. data/lib/upsert/connection/sqlite3_database.rb +36 -0
  14. data/lib/upsert/row.rb +28 -24
  15. data/lib/upsert/version.rb +1 -1
  16. data/spec/active_record_upsert_spec.rb +16 -0
  17. data/spec/binary_spec.rb +21 -0
  18. data/spec/correctness_spec.rb +73 -0
  19. data/spec/database_functions_spec.rb +36 -0
  20. data/spec/database_spec.rb +97 -0
  21. data/spec/logger_spec.rb +37 -0
  22. data/{test → spec}/misc/get_postgres_reserved_words.rb +0 -0
  23. data/{test → spec}/misc/mysql_reserved.txt +0 -0
  24. data/{test → spec}/misc/pg_reserved.txt +0 -0
  25. data/spec/multibyte_spec.rb +27 -0
  26. data/spec/precision_spec.rb +11 -0
  27. data/spec/reserved_words_spec.rb +46 -0
  28. data/{test/helper.rb → spec/spec_helper.rb} +43 -43
  29. data/spec/speed_spec.rb +73 -0
  30. data/spec/threaded_spec.rb +34 -0
  31. data/spec/timezones_spec.rb +28 -0
  32. data/upsert.gemspec +6 -2
  33. metadata +99 -50
  34. data/lib/upsert/mysql2_client.rb +0 -104
  35. data/lib/upsert/pg_connection.rb +0 -92
  36. data/lib/upsert/pg_connection/column_definition.rb +0 -35
  37. data/lib/upsert/sqlite3_database.rb +0 -39
  38. data/test/shared/binary.rb +0 -18
  39. data/test/shared/correctness.rb +0 -72
  40. data/test/shared/database.rb +0 -94
  41. data/test/shared/multibyte.rb +0 -37
  42. data/test/shared/precision.rb +0 -8
  43. data/test/shared/reserved_words.rb +0 -45
  44. data/test/shared/speed.rb +0 -72
  45. data/test/shared/threaded.rb +0 -31
  46. data/test/shared/timezones.rb +0 -25
  47. data/test/test_active_record_connection_adapter.rb +0 -36
  48. data/test/test_active_record_upsert.rb +0 -23
  49. data/test/test_mysql2.rb +0 -43
  50. data/test/test_pg.rb +0 -45
  51. data/test/test_sqlite.rb +0 -47
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ describe Upsert do
3
+ describe "logger" do
4
+ it "logs to stderr by default" do
5
+ begin
6
+ old_stderr = $stderr
7
+ old_logger = Upsert.logger
8
+ Upsert.logger = nil
9
+ $stderr = StringIO.new
10
+ Upsert.logger.warn "hello"
11
+ $stderr.rewind
12
+ $stderr.read.chomp.should == 'hello'
13
+ ensure
14
+ Upsert.logger = old_logger
15
+ $stderr = old_stderr
16
+ end
17
+ end
18
+
19
+ it "logs queries" do
20
+ require 'sqlite3'
21
+ db = SQLite3::Database.open(':memory:')
22
+ db.execute_batch "CREATE TABLE cats (name CHARACTER VARYING(255))"
23
+ begin
24
+ io = StringIO.new
25
+ old_logger = Upsert.logger
26
+ Upsert.logger = Logger.new io, Logger::DEBUG
27
+ u = Upsert.new(db, :cats)
28
+ u.row :name => 'you'
29
+ io.rewind
30
+ io.read.chomp.should =~ /INSERT OR IGNORE.*you/i
31
+ ensure
32
+ Upsert.logger = old_logger
33
+ end
34
+ end
35
+
36
+ end
37
+ end
File without changes
File without changes
File without changes
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'spec_helper'
3
+ describe Upsert do
4
+ describe "supports multibyte" do
5
+ it "works one-by-one" do
6
+ assert_creates(Pet, [{:name => 'I♥NY', :gender => 'périferôl'}]) do
7
+ upsert = Upsert.new $conn, :pets
8
+ upsert.row({:name => 'I♥NY'}, {:gender => 'périferôl'})
9
+ end
10
+ end
11
+ it "works serially" do
12
+ assert_creates(Pet, [{:name => 'I♥NY', :gender => 'jÚrgen'}]) do
13
+ upsert = Upsert.new $conn, :pets
14
+ upsert.row({:name => 'I♥NY'}, {:gender => 'périferôl'})
15
+ upsert.row({:name => 'I♥NY'}, {:gender => 'jÚrgen'})
16
+ end
17
+ end
18
+ it "works batch" do
19
+ assert_creates(Pet, [{:name => 'I♥NY', :gender => 'jÚrgen'}]) do
20
+ Upsert.batch($conn, :pets) do |upsert|
21
+ upsert.row({:name => 'I♥NY'}, {:gender => 'périferôl'})
22
+ upsert.row({:name => 'I♥NY'}, {:gender => 'jÚrgen'})
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ describe Upsert do
3
+ describe "is precise" do
4
+ it "stores small numbers precisely" do
5
+ small = -0.00000000634943
6
+ upsert = Upsert.new $conn, :pets
7
+ upsert.row({:name => 'NotJerry'}, :lovability => small)
8
+ Pet.first.lovability.should == small
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ describe Upsert do
3
+ describe "doesn't blow up on reserved words" do
4
+ # collect and uniq reserved words
5
+ reserved_words = ['mysql_reserved.txt', 'pg_reserved.txt'].map do |basename|
6
+ File.expand_path("../misc/#{basename}", __FILE__)
7
+ end.map do |path|
8
+ IO.readlines(path)
9
+ end.flatten.map(&:chomp).select(&:present?).uniq
10
+
11
+ # make lots of AR models, each of which has 10 columns named after these words
12
+ nasties = []
13
+ reserved_words.each_slice(10) do |words|
14
+ eval %{
15
+ class Nasty#{nasties.length} < ActiveRecord::Base
16
+ end
17
+ }
18
+ nasty = Object.const_get("Nasty#{nasties.length}")
19
+ nasty.class_eval do
20
+ self.primary_key = 'fake_primary_key'
21
+ col :fake_primary_key
22
+ words.each do |word|
23
+ col word
24
+ end
25
+ end
26
+ nasties << [ nasty, words ]
27
+ end
28
+ nasties.each do |nasty, _|
29
+ nasty.auto_upgrade!
30
+ end
31
+
32
+ describe "reserved words" do
33
+ nasties.each do |nasty, words|
34
+ it "doesn't die on reserved words #{words.join(',')}" do
35
+ upsert = Upsert.new $conn, nasty.table_name
36
+ random = rand(1e3).to_s
37
+ selector = { :fake_primary_key => random, words.first => words.first }
38
+ document = words[1..-1].inject({}) { |memo, word| memo[word] = word; memo }
39
+ assert_creates nasty, [selector.merge(document)] do
40
+ upsert.row selector, document
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,22 +1,34 @@
1
- require 'rubygems'
2
1
  require 'bundler/setup'
3
- require 'securerandom'
4
- require 'zlib'
5
- require 'benchmark'
6
- require 'faker'
7
- require 'minitest/spec'
8
- require 'minitest/autorun'
9
- require 'minitest/reporters'
10
- MiniTest::Unit.runner = MiniTest::SuiteRunner.new
11
- MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new
12
2
 
13
3
  require 'active_record'
14
- require 'activerecord-import'
15
4
  require 'active_record_inline_schema'
5
+ require 'activerecord-import'
16
6
 
17
- # require 'logger'
18
- # ActiveRecord::Base.logger = Logger.new($stdout)
19
- # ActiveRecord::Base.logger.level = Logger::DEBUG
7
+ ENV['ADAPTER'] ||= 'mysql2'
8
+
9
+ case ENV['ADAPTER']
10
+ when 'postgresql'
11
+ system %{ dropdb upsert_test }
12
+ system %{ createdb upsert_test }
13
+ ActiveRecord::Base.establish_connection :adapter => 'postgresql', :database => 'upsert_test'
14
+ $conn = PGconn.new(:dbname => 'upsert_test')
15
+ when 'mysql2'
16
+ system %{ mysql -u root -ppassword -e "DROP DATABASE IF EXISTS upsert_test" }
17
+ system %{ mysql -u root -ppassword -e "CREATE DATABASE upsert_test CHARSET utf8" }
18
+ ActiveRecord::Base.establish_connection 'mysql2://root:password@127.0.0.1/upsert_test'
19
+ $conn = Mysql2::Client.new(:username => 'root', :password => 'password', :database => 'upsert_test')
20
+ when 'sqlite3'
21
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
22
+ $conn = ActiveRecord::Base.connection.raw_connection
23
+ else
24
+ raise "not supported"
25
+ end
26
+
27
+ if ENV['UPSERT_DEBUG'] == 'true'
28
+ require 'logger'
29
+ ActiveRecord::Base.logger = Logger.new($stdout)
30
+ ActiveRecord::Base.logger.level = Logger::DEBUG
31
+ end
20
32
 
21
33
  class Pet < ActiveRecord::Base
22
34
  col :name
@@ -31,16 +43,14 @@ class Pet < ActiveRecord::Base
31
43
  col :home_address, :type => :text
32
44
  add_index :name, :unique => true
33
45
  end
46
+ Pet.auto_upgrade!
34
47
 
35
- # ENV['UPSERT_DEBUG'] = 'true'
36
-
37
- require 'upsert'
38
-
39
- MiniTest::Spec.class_eval do
40
- def self.shared_examples
41
- @shared_examples ||= {}
42
- end
48
+ require 'securerandom'
49
+ require 'zlib'
50
+ require 'benchmark'
51
+ require 'faker'
43
52
 
53
+ module SpecHelper
44
54
  def lotsa_records
45
55
  @records ||= begin
46
56
  memo = []
@@ -77,22 +87,22 @@ MiniTest::Spec.class_eval do
77
87
 
78
88
  Pet.delete_all
79
89
 
80
- Upsert.batch(connection, :pets) do |upsert|
90
+ Upsert.batch($conn, :pets) do |upsert|
81
91
  records.each do |selector, document|
82
92
  upsert.row(selector, document)
83
93
  end
84
94
  end
85
95
  ref2 = Pet.order(:name).all.map { |pet| pet.attributes.except('id') }
86
- ref2.must_equal ref1
96
+ ref2.should == ref1
87
97
  end
88
98
 
89
99
  def assert_creates(model, expected_records)
90
100
  expected_records.each do |conditions|
91
- model.where(conditions).count.must_equal 0
101
+ model.where(conditions).count.should == 0
92
102
  end
93
103
  yield
94
104
  expected_records.each do |conditions|
95
- model.where(conditions).count.must_equal 1
105
+ model.where(conditions).count.should == 1
96
106
  end
97
107
  end
98
108
 
@@ -109,32 +119,22 @@ MiniTest::Spec.class_eval do
109
119
  sleep 1
110
120
 
111
121
  upsert_time = Benchmark.realtime do
112
- Upsert.batch(connection, :pets) do |upsert|
122
+ Upsert.batch($conn, :pets) do |upsert|
113
123
  records.each do |selector, document|
114
124
  upsert.row(selector, document)
115
125
  end
116
126
  end
117
127
  end
118
- upsert_time.must_be :<, ar_time
128
+ upsert_time.should be < ar_time
119
129
  $stderr.puts " Upsert was #{((ar_time - upsert_time) / ar_time * 100).round}% faster than #{competition}"
120
130
  end
121
131
  end
122
132
 
123
- module MiniTest::Spec::SharedExamples
124
- def shared_examples_for(desc, &block)
125
- MiniTest::Spec.shared_examples[desc] = block
126
- end
127
-
128
- def it_also(desc)
129
- self.instance_eval(&MiniTest::Spec.shared_examples[desc])# do
130
- # describe desc do
131
- # .call
132
- # end
133
- # end
133
+ RSpec.configure do |c|
134
+ c.include SpecHelper
135
+ c.before do
136
+ Pet.delete_all
134
137
  end
135
138
  end
136
139
 
137
- Object.class_eval { include(MiniTest::Spec::SharedExamples) }
138
- Dir[File.expand_path("../shared/*.rb", __FILE__)].each do |path|
139
- require path
140
- end
140
+ require 'upsert'
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+ describe Upsert do
3
+ describe "can be speeded up with upserting" do
4
+ describe 'compared to native ActiveRecord' do
5
+ it "is faster than new/set/save" do
6
+ assert_faster_than 'find + new/set/save', lotsa_records do |records|
7
+ records.each do |selector, document|
8
+ if pet = Pet.where(selector).first
9
+ pet.update_attributes document, :without_protection => true
10
+ else
11
+ pet = Pet.new
12
+ selector.each do |k, v|
13
+ pet.send "#{k}=", v
14
+ end
15
+ document.each do |k, v|
16
+ pet.send "#{k}=", v
17
+ end
18
+ pet.save!
19
+ end
20
+ end
21
+ end
22
+ end
23
+ it "is faster than find_or_create + update_attributes" do
24
+ assert_faster_than 'find_or_create + update_attributes', lotsa_records do |records|
25
+ dynamic_method = nil
26
+ records.each do |selector, document|
27
+ dynamic_method ||= "find_or_create_by_#{selector.keys.join('_or_')}"
28
+ pet = Pet.send(dynamic_method, *selector.values)
29
+ pet.update_attributes document, :without_protection => true
30
+ end
31
+ end
32
+ end
33
+ it "is faster than create + rescue/find/update" do
34
+ assert_faster_than 'create + rescue/find/update', lotsa_records do |records|
35
+ dynamic_method = nil
36
+ records.each do |selector, document|
37
+ dynamic_method ||= "find_or_create_by_#{selector.keys.join('_or_')}"
38
+ begin
39
+ Pet.create selector.merge(document), :without_protection => true
40
+ rescue
41
+ pet = Pet.send(dynamic_method, *selector.values)
42
+ pet.update_attributes document, :without_protection => true
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ if ENV['ADAPTER'] == 'mysql2'
50
+ describe 'compared to activerecord-import' do
51
+ it "is faster than faking upserts with activerecord-import" do
52
+ assert_faster_than 'faking upserts with activerecord-import', lotsa_records do |records|
53
+ columns = nil
54
+ all_values = []
55
+ records.each do |selector, document|
56
+ columns ||= (selector.keys + document.keys).uniq
57
+ all_values << columns.map do |k|
58
+ if document.has_key?(k)
59
+ # prefer the document so that you can change rows
60
+ document[k]
61
+ else
62
+ selector[k]
63
+ end
64
+ end
65
+ end
66
+ Pet.import columns, all_values, :timestamps => false, :on_duplicate_key_update => columns
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ describe Upsert do
3
+ describe "is thread-safe" do
4
+ it "is safe to use one-by-one" do
5
+ upsert = Upsert.new $conn, :pets
6
+ assert_creates(Pet, [{:name => 'Jerry', :gender => 'neutered'}]) do
7
+ ts = []
8
+ 10.times do
9
+ ts << Thread.new do
10
+ sleep 0.2
11
+ upsert.row({:name => 'Jerry'}, :gender => 'male')
12
+ upsert.row({:name => 'Jerry'}, :gender => 'neutered')
13
+ end
14
+ ts.each { |t| t.join }
15
+ end
16
+ end
17
+ end
18
+ it "is safe to use batch" do
19
+ assert_creates(Pet, [{:name => 'Jerry', :gender => 'neutered'}]) do
20
+ Upsert.batch($conn, :pets) do |upsert|
21
+ ts = []
22
+ 10.times do
23
+ ts << Thread.new do
24
+ sleep 0.2
25
+ upsert.row({:name => 'Jerry'}, :gender => 'male')
26
+ upsert.row({:name => 'Jerry'}, :gender => 'neutered')
27
+ end
28
+ ts.each { |t| t.join }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ describe Upsert do
3
+ describe "doesn't mess with timezones" do
4
+ before do
5
+ @old_default_tz = ActiveRecord::Base.default_timezone
6
+ end
7
+ after do
8
+ ActiveRecord::Base.default_timezone = @old_default_tz
9
+ end
10
+
11
+ it "deals fine with UTC" do
12
+ ActiveRecord::Base.default_timezone = :utc
13
+ time = Time.now.utc
14
+ upsert = Upsert.new $conn, :pets
15
+ assert_creates(Pet, [{:name => 'Jerry', :morning_walk_time => time}]) do
16
+ upsert.row({:name => 'Jerry'}, {:morning_walk_time => time})
17
+ end
18
+ end
19
+ it "won't mess with UTC" do
20
+ ActiveRecord::Base.default_timezone = :local
21
+ time = Time.now
22
+ upsert = Upsert.new $conn, :pets
23
+ assert_creates(Pet, [{:name => 'Jerry', :morning_walk_time => time}]) do
24
+ upsert.row({:name => 'Jerry'}, {:morning_walk_time => time})
25
+ end
26
+ end
27
+ end
28
+ end
data/upsert.gemspec CHANGED
@@ -15,14 +15,18 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Upsert::VERSION
17
17
 
18
+ gem.add_development_dependency 'posix-spawn'
19
+ gem.add_development_dependency 'rspec-core'
20
+ gem.add_development_dependency 'rspec-expectations'
21
+ gem.add_development_dependency 'rspec-mocks'
22
+
18
23
  gem.add_development_dependency 'sqlite3'
19
24
  gem.add_development_dependency 'mysql2'
20
25
  gem.add_development_dependency 'pg'
21
26
  gem.add_development_dependency 'activerecord' # testing only
22
27
  gem.add_development_dependency 'active_record_inline_schema'
23
28
  gem.add_development_dependency 'faker'
24
- gem.add_development_dependency 'minitest'
25
- gem.add_development_dependency 'minitest-reporters'
26
29
  gem.add_development_dependency 'yard'
27
30
  gem.add_development_dependency 'activerecord-import'
31
+ gem.add_development_dependency 'pry'
28
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: upsert
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,10 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-03 00:00:00.000000000 Z
12
+ date: 2012-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: sqlite3
15
+ name: posix-spawn
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
@@ -28,7 +28,7 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
30
  - !ruby/object:Gem::Dependency
31
- name: mysql2
31
+ name: rspec-core
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
@@ -44,7 +44,7 @@ dependencies:
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
46
  - !ruby/object:Gem::Dependency
47
- name: pg
47
+ name: rspec-expectations
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
@@ -60,7 +60,7 @@ dependencies:
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  - !ruby/object:Gem::Dependency
63
- name: activerecord
63
+ name: rspec-mocks
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  none: false
66
66
  requirements:
@@ -76,7 +76,7 @@ dependencies:
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  - !ruby/object:Gem::Dependency
79
- name: active_record_inline_schema
79
+ name: sqlite3
80
80
  requirement: !ruby/object:Gem::Requirement
81
81
  none: false
82
82
  requirements:
@@ -92,7 +92,7 @@ dependencies:
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
94
  - !ruby/object:Gem::Dependency
95
- name: faker
95
+ name: mysql2
96
96
  requirement: !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
@@ -108,7 +108,7 @@ dependencies:
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  - !ruby/object:Gem::Dependency
111
- name: minitest
111
+ name: pg
112
112
  requirement: !ruby/object:Gem::Requirement
113
113
  none: false
114
114
  requirements:
@@ -124,7 +124,39 @@ dependencies:
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  - !ruby/object:Gem::Dependency
127
- name: minitest-reporters
127
+ name: activerecord
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: active_record_inline_schema
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: faker
128
160
  requirement: !ruby/object:Gem::Requirement
129
161
  none: false
130
162
  requirements:
@@ -171,6 +203,22 @@ dependencies:
171
203
  - - ! '>='
172
204
  - !ruby/object:Gem::Version
173
205
  version: '0'
206
+ - !ruby/object:Gem::Dependency
207
+ name: pry
208
+ requirement: !ruby/object:Gem::Requirement
209
+ none: false
210
+ requirements:
211
+ - - ! '>='
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ none: false
218
+ requirements:
219
+ - - ! '>='
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
174
222
  description: Upsert for MySQL, PostgreSQL, and SQLite. Codifies various SQL MERGE
175
223
  tricks like MySQL's ON DUPLICATE KEY UPDATE, PostgreSQL's CREATE FUNCTION merge_db,
176
224
  and SQLite's INSERT OR IGNORE.
@@ -190,30 +238,33 @@ files:
190
238
  - lib/upsert.rb
191
239
  - lib/upsert/active_record_upsert.rb
192
240
  - lib/upsert/binary.rb
193
- - lib/upsert/mysql2_client.rb
194
- - lib/upsert/pg_connection.rb
195
- - lib/upsert/pg_connection/column_definition.rb
241
+ - lib/upsert/buffer.rb
242
+ - lib/upsert/buffer/mysql2_client.rb
243
+ - lib/upsert/buffer/pg_connection.rb
244
+ - lib/upsert/buffer/pg_connection/merge_function.rb
245
+ - lib/upsert/buffer/sqlite3_database.rb
246
+ - lib/upsert/connection.rb
247
+ - lib/upsert/connection/mysql2_client.rb
248
+ - lib/upsert/connection/pg_connection.rb
249
+ - lib/upsert/connection/sqlite3_database.rb
196
250
  - lib/upsert/row.rb
197
- - lib/upsert/sqlite3_database.rb
198
251
  - lib/upsert/version.rb
199
- - test/helper.rb
200
- - test/misc/get_postgres_reserved_words.rb
201
- - test/misc/mysql_reserved.txt
202
- - test/misc/pg_reserved.txt
203
- - test/shared/binary.rb
204
- - test/shared/correctness.rb
205
- - test/shared/database.rb
206
- - test/shared/multibyte.rb
207
- - test/shared/precision.rb
208
- - test/shared/reserved_words.rb
209
- - test/shared/speed.rb
210
- - test/shared/threaded.rb
211
- - test/shared/timezones.rb
212
- - test/test_active_record_connection_adapter.rb
213
- - test/test_active_record_upsert.rb
214
- - test/test_mysql2.rb
215
- - test/test_pg.rb
216
- - test/test_sqlite.rb
252
+ - spec/active_record_upsert_spec.rb
253
+ - spec/binary_spec.rb
254
+ - spec/correctness_spec.rb
255
+ - spec/database_functions_spec.rb
256
+ - spec/database_spec.rb
257
+ - spec/logger_spec.rb
258
+ - spec/misc/get_postgres_reserved_words.rb
259
+ - spec/misc/mysql_reserved.txt
260
+ - spec/misc/pg_reserved.txt
261
+ - spec/multibyte_spec.rb
262
+ - spec/precision_spec.rb
263
+ - spec/reserved_words_spec.rb
264
+ - spec/spec_helper.rb
265
+ - spec/speed_spec.rb
266
+ - spec/threaded_spec.rb
267
+ - spec/timezones_spec.rb
217
268
  - upsert.gemspec
218
269
  homepage: https://github.com/seamusabshere/upsert
219
270
  licenses: []
@@ -241,22 +292,20 @@ specification_version: 3
241
292
  summary: Upsert for MySQL, PostgreSQL, and SQLite. Finally, all those SQL MERGE tricks
242
293
  codified.
243
294
  test_files:
244
- - test/helper.rb
245
- - test/misc/get_postgres_reserved_words.rb
246
- - test/misc/mysql_reserved.txt
247
- - test/misc/pg_reserved.txt
248
- - test/shared/binary.rb
249
- - test/shared/correctness.rb
250
- - test/shared/database.rb
251
- - test/shared/multibyte.rb
252
- - test/shared/precision.rb
253
- - test/shared/reserved_words.rb
254
- - test/shared/speed.rb
255
- - test/shared/threaded.rb
256
- - test/shared/timezones.rb
257
- - test/test_active_record_connection_adapter.rb
258
- - test/test_active_record_upsert.rb
259
- - test/test_mysql2.rb
260
- - test/test_pg.rb
261
- - test/test_sqlite.rb
295
+ - spec/active_record_upsert_spec.rb
296
+ - spec/binary_spec.rb
297
+ - spec/correctness_spec.rb
298
+ - spec/database_functions_spec.rb
299
+ - spec/database_spec.rb
300
+ - spec/logger_spec.rb
301
+ - spec/misc/get_postgres_reserved_words.rb
302
+ - spec/misc/mysql_reserved.txt
303
+ - spec/misc/pg_reserved.txt
304
+ - spec/multibyte_spec.rb
305
+ - spec/precision_spec.rb
306
+ - spec/reserved_words_spec.rb
307
+ - spec/spec_helper.rb
308
+ - spec/speed_spec.rb
309
+ - spec/threaded_spec.rb
310
+ - spec/timezones_spec.rb
262
311
  has_rdoc: