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.
- 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:
|