upsert 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/README.md +6 -9
- data/Rakefile +9 -14
- data/lib/upsert.rb +40 -71
- data/lib/upsert/buffer.rb +36 -0
- data/lib/upsert/buffer/mysql2_client.rb +67 -0
- data/lib/upsert/buffer/pg_connection.rb +54 -0
- data/lib/upsert/buffer/pg_connection/merge_function.rb +138 -0
- data/lib/upsert/buffer/sqlite3_database.rb +13 -0
- data/lib/upsert/connection.rb +41 -0
- data/lib/upsert/connection/mysql2_client.rb +53 -0
- data/lib/upsert/connection/pg_connection.rb +39 -0
- data/lib/upsert/connection/sqlite3_database.rb +36 -0
- data/lib/upsert/row.rb +28 -24
- data/lib/upsert/version.rb +1 -1
- data/spec/active_record_upsert_spec.rb +16 -0
- data/spec/binary_spec.rb +21 -0
- data/spec/correctness_spec.rb +73 -0
- data/spec/database_functions_spec.rb +36 -0
- data/spec/database_spec.rb +97 -0
- data/spec/logger_spec.rb +37 -0
- data/{test → spec}/misc/get_postgres_reserved_words.rb +0 -0
- data/{test → spec}/misc/mysql_reserved.txt +0 -0
- data/{test → spec}/misc/pg_reserved.txt +0 -0
- data/spec/multibyte_spec.rb +27 -0
- data/spec/precision_spec.rb +11 -0
- data/spec/reserved_words_spec.rb +46 -0
- data/{test/helper.rb → spec/spec_helper.rb} +43 -43
- data/spec/speed_spec.rb +73 -0
- data/spec/threaded_spec.rb +34 -0
- data/spec/timezones_spec.rb +28 -0
- data/upsert.gemspec +6 -2
- metadata +99 -50
- data/lib/upsert/mysql2_client.rb +0 -104
- data/lib/upsert/pg_connection.rb +0 -92
- data/lib/upsert/pg_connection/column_definition.rb +0 -35
- data/lib/upsert/sqlite3_database.rb +0 -39
- data/test/shared/binary.rb +0 -18
- data/test/shared/correctness.rb +0 -72
- data/test/shared/database.rb +0 -94
- data/test/shared/multibyte.rb +0 -37
- data/test/shared/precision.rb +0 -8
- data/test/shared/reserved_words.rb +0 -45
- data/test/shared/speed.rb +0 -72
- data/test/shared/threaded.rb +0 -31
- data/test/shared/timezones.rb +0 -25
- data/test/test_active_record_connection_adapter.rb +0 -36
- data/test/test_active_record_upsert.rb +0 -23
- data/test/test_mysql2.rb +0 -43
- data/test/test_pg.rb +0 -45
- data/test/test_sqlite.rb +0 -47
data/spec/logger_spec.rb
ADDED
@@ -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
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
36
|
-
|
37
|
-
require '
|
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(
|
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.
|
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.
|
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.
|
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(
|
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.
|
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
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
138
|
-
Dir[File.expand_path("../shared/*.rb", __FILE__)].each do |path|
|
139
|
-
require path
|
140
|
-
end
|
140
|
+
require 'upsert'
|
data/spec/speed_spec.rb
ADDED
@@ -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.
|
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-
|
12
|
+
date: 2012-09-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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/
|
194
|
-
- lib/upsert/
|
195
|
-
- lib/upsert/pg_connection
|
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
|
-
-
|
200
|
-
-
|
201
|
-
-
|
202
|
-
-
|
203
|
-
-
|
204
|
-
-
|
205
|
-
-
|
206
|
-
-
|
207
|
-
-
|
208
|
-
-
|
209
|
-
-
|
210
|
-
-
|
211
|
-
-
|
212
|
-
-
|
213
|
-
-
|
214
|
-
-
|
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
|
-
-
|
245
|
-
-
|
246
|
-
-
|
247
|
-
-
|
248
|
-
-
|
249
|
-
-
|
250
|
-
-
|
251
|
-
-
|
252
|
-
-
|
253
|
-
-
|
254
|
-
-
|
255
|
-
-
|
256
|
-
-
|
257
|
-
-
|
258
|
-
-
|
259
|
-
-
|
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:
|