upsert 0.0.1 → 0.1.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.
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ shared_examples_for "supports multibyte" do
3
+ describe :multibyte do
4
+ it "works one-by-one" do
5
+ upsert = Upsert.new connection, :pets
6
+ assert_creates(Pet, [{:name => 'I♥NY', :gender => 'périferôl'}]) do
7
+ upsert.row({:name => 'I♥NY'}, {:gender => 'périferôl'})
8
+ end
9
+ end
10
+ it "works serially" do
11
+ upsert = Upsert.new connection, :pets
12
+ assert_creates(Pet, [{:name => 'I♥NY', :gender => 'jÚrgen'}]) do
13
+ upsert.row({:name => 'I♥NY'}, {:gender => 'périferôl'})
14
+ upsert.row({:name => 'I♥NY'}, {:gender => 'jÚrgen'})
15
+ end
16
+ end
17
+ it "works multi" do
18
+ assert_creates(Pet, [{:name => 'I♥NY', :gender => 'jÚrgen'}]) do
19
+ Upsert.new(connection, :pets).multi do |xxx|
20
+ xxx.row({:name => 'I♥NY'}, {:gender => 'périferôl'})
21
+ xxx.row({:name => 'I♥NY'}, {:gender => 'jÚrgen'})
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,72 @@
1
+ shared_examples_for 'can be speeded up with upserting' do
2
+ describe :speed do
3
+ describe 'compared to native ActiveRecord' do
4
+ it "is faster than new/set/save" do
5
+ assert_faster_than 'find + new/set/save', lotsa_records do |records|
6
+ records.each do |selector, document|
7
+ if pet = Pet.where(selector).first
8
+ pet.update_attributes document, :without_protection => true
9
+ else
10
+ pet = Pet.new
11
+ selector.each do |k, v|
12
+ pet.send "#{k}=", v
13
+ end
14
+ document.each do |k, v|
15
+ pet.send "#{k}=", v
16
+ end
17
+ pet.save!
18
+ end
19
+ end
20
+ end
21
+ end
22
+ it "is faster than find_or_create + update_attributes" do
23
+ assert_faster_than 'find_or_create + update_attributes', lotsa_records do |records|
24
+ dynamic_method = nil
25
+ records.each do |selector, document|
26
+ dynamic_method ||= "find_or_create_by_#{selector.keys.join('_or_')}"
27
+ pet = Pet.send(dynamic_method, *selector.values)
28
+ pet.update_attributes document, :without_protection => true
29
+ end
30
+ end
31
+ end
32
+ it "is faster than create + rescue/find/update" do
33
+ assert_faster_than 'create + rescue/find/update', lotsa_records do |records|
34
+ dynamic_method = nil
35
+ records.each do |selector, document|
36
+ dynamic_method ||= "find_or_create_by_#{selector.keys.join('_or_')}"
37
+ begin
38
+ Pet.create selector.merge(document), :without_protection => true
39
+ rescue
40
+ pet = Pet.send(dynamic_method, *selector.values)
41
+ pet.update_attributes document, :without_protection => true
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ describe 'compared to activerecord-import' do
49
+ it "is faster than faking upserts with activerecord-import" do
50
+ unless Pet.connection.respond_to?(:sql_for_on_duplicate_key_update)
51
+ flunk "#{Pet.connection} does not support activerecord-import's :on_duplicate_key_update"
52
+ end
53
+ assert_faster_than 'faking upserts with activerecord-import', lotsa_records do |records|
54
+ columns = nil
55
+ all_values = []
56
+ records.each do |selector, document|
57
+ columns ||= (selector.keys + document.keys).uniq
58
+ all_values << columns.map do |k|
59
+ if document.has_key?(k)
60
+ # prefer the document so that you can change rows
61
+ document[k]
62
+ else
63
+ selector[k]
64
+ end
65
+ end
66
+ end
67
+ Pet.import columns, all_values, :timestamps => false, :on_duplicate_key_update => columns
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,27 @@
1
+ shared_examples_for "doesn't mess with timezones" do
2
+ describe :timezones do
3
+ before do
4
+ @old_default_tz = ActiveRecord::Base.default_timezone
5
+ end
6
+ after do
7
+ ActiveRecord::Base.default_timezone = @old_default_tz
8
+ end
9
+
10
+ it "deals fine with UTC" do
11
+ ActiveRecord::Base.default_timezone = :utc
12
+ time = Time.now.utc
13
+ upsert = Upsert.new connection, :pets
14
+ assert_creates(Pet, [{:name => 'Jerry', :morning_walk_time => time}]) do
15
+ upsert.row({:name => 'Jerry'}, {:morning_walk_time => time})
16
+ end
17
+ end
18
+ it "won't mess with UTC" do
19
+ ActiveRecord::Base.default_timezone = :local
20
+ time = Time.now
21
+ upsert = Upsert.new connection, :pets
22
+ assert_creates(Pet, [{:name => 'Jerry', :morning_walk_time => time}]) do
23
+ upsert.row({:name => 'Jerry'}, {:morning_walk_time => time})
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ require 'helper'
2
+
3
+ system %{ mysql -u root -ppassword -e "DROP DATABASE IF EXISTS test_upsert; CREATE DATABASE test_upsert CHARSET utf8" }
4
+ ActiveRecord::Base.establish_connection :adapter => 'mysql2', :username => 'root', :password => 'password', :database => 'test_upsert', :pool => 2
5
+
6
+ describe "using an ActiveRecord connection adapter" do
7
+ before do
8
+ ActiveRecord::Base.connection.drop_table(Pet.table_name) rescue nil
9
+ Pet.auto_upgrade!
10
+ @opened_connections = []
11
+ @connection = new_connection
12
+ end
13
+ after do
14
+ @opened_connections.each { |c| ActiveRecord::Base.connection_pool.checkin(c) }
15
+ end
16
+ def new_connection
17
+ c = ActiveRecord::Base.connection_pool.checkout
18
+ @opened_connections << c
19
+ c
20
+ end
21
+ def connection
22
+ @connection
23
+ end
24
+
25
+ it_also 'is a database with an upsert trick'
26
+
27
+ it_also 'is just as correct as other ways'
28
+
29
+ it_also 'can be speeded up with upserting'
30
+
31
+ it_also 'supports binary upserts'
32
+
33
+ it_also "supports multibyte"
34
+
35
+ it_also "doesn't mess with timezones"
36
+ end
data/test/test_mysql2.rb CHANGED
@@ -6,7 +6,7 @@ ActiveRecord::Base.establish_connection :adapter => 'mysql2', :username => 'root
6
6
 
7
7
  describe "upserting on mysql2" do
8
8
  before do
9
- ActiveRecord::Base.connection.drop_table Pet.table_name rescue nil
9
+ ActiveRecord::Base.connection.drop_table(Pet.table_name) rescue nil
10
10
  Pet.auto_upgrade!
11
11
  @opened_connections = []
12
12
  @connection = new_connection
@@ -23,6 +23,15 @@ describe "upserting on mysql2" do
23
23
  @connection
24
24
  end
25
25
 
26
- it_behaves_like :database
26
+ it_also 'is a database with an upsert trick'
27
27
 
28
+ it_also 'is just as correct as other ways'
29
+
30
+ it_also 'can be speeded up with upserting'
31
+
32
+ it_also 'supports binary upserts'
33
+
34
+ it_also "supports multibyte"
35
+
36
+ it_also "doesn't mess with timezones"
28
37
  end
data/test/test_pg.rb CHANGED
@@ -7,7 +7,7 @@ ActiveRecord::Base.establish_connection :adapter => 'postgresql', :database => '
7
7
 
8
8
  describe "upserting on postgresql" do
9
9
  before do
10
- ActiveRecord::Base.connection.drop_table Pet.table_name rescue nil
10
+ ActiveRecord::Base.connection.drop_table(Pet.table_name) rescue nil
11
11
  Pet.auto_upgrade!
12
12
  @opened_connections = []
13
13
  @connection = new_connection
@@ -24,6 +24,15 @@ describe "upserting on postgresql" do
24
24
  @connection
25
25
  end
26
26
 
27
- it_behaves_like :database
27
+ it_also 'is a database with an upsert trick'
28
28
 
29
+ it_also 'is just as correct as other ways'
30
+
31
+ it_also 'can be speeded up with upserting'
32
+
33
+ it_also 'supports binary upserts'
34
+
35
+ it_also "supports multibyte"
36
+
37
+ it_also "doesn't mess with timezones"
29
38
  end
data/test/test_sqlite.rb CHANGED
@@ -8,17 +8,33 @@ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => db_p
8
8
 
9
9
  describe "upserting on sqlite" do
10
10
  before do
11
- ActiveRecord::Base.connection.drop_table Pet.table_name rescue nil
11
+ ActiveRecord::Base.connection.drop_table(Pet.table_name) rescue nil
12
12
  Pet.auto_upgrade!
13
+ @opened_connections = []
13
14
  @connection = new_connection
14
15
  end
16
+ after do
17
+ @opened_connections.each { |c| c.close }
18
+ end
19
+
15
20
  def new_connection
16
- db_path = File.expand_path('../../tmp/test.sqlite3', __FILE__)
17
- SQLite3::Database.open(db_path)
21
+ c = SQLite3::Database.open(File.expand_path('../../tmp/test.sqlite3', __FILE__))
22
+ @opened_connections << c
23
+ c
18
24
  end
19
25
  def connection
20
26
  @connection
21
27
  end
22
28
 
23
- it_behaves_like :database
29
+ it_also 'is a database with an upsert trick'
30
+
31
+ it_also 'is just as correct as other ways'
32
+
33
+ it_also 'can be speeded up with upserting'
34
+
35
+ it_also "supports multibyte"
36
+
37
+ it_also "doesn't mess with timezones"
38
+
39
+ it_also 'supports binary upserts'
24
40
  end
data/upsert.gemspec CHANGED
@@ -20,7 +20,9 @@ Gem::Specification.new do |gem|
20
20
  gem.add_development_dependency 'pg'
21
21
  gem.add_development_dependency 'activerecord' # testing only
22
22
  gem.add_development_dependency 'active_record_inline_schema'
23
+ gem.add_development_dependency 'faker'
23
24
  gem.add_development_dependency 'minitest'
24
25
  gem.add_development_dependency 'minitest-reporters'
25
26
  gem.add_development_dependency 'yard'
27
+ gem.add_development_dependency 'activerecord-import'
26
28
  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.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-13 00:00:00.000000000 Z
12
+ date: 2012-06-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sqlite3
@@ -91,6 +91,22 @@ dependencies:
91
91
  - - ! '>='
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: faker
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
94
110
  - !ruby/object:Gem::Dependency
95
111
  name: minitest
96
112
  requirement: !ruby/object:Gem::Requirement
@@ -139,6 +155,22 @@ dependencies:
139
155
  - - ! '>='
140
156
  - !ruby/object:Gem::Version
141
157
  version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: activerecord-import
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
142
174
  description: Upsert for MySQL, PostgreSQL, and SQLite. Codifies various SQL MERGE
143
175
  tricks like MySQL's ON DUPLICATE KEY UPDATE, PostgreSQL's CREATE FUNCTION merge_db,
144
176
  and SQLite's INSERT OR IGNORE.
@@ -149,11 +181,13 @@ extensions: []
149
181
  extra_rdoc_files: []
150
182
  files:
151
183
  - .gitignore
184
+ - .yardopts
152
185
  - Gemfile
153
186
  - LICENSE
154
187
  - README.md
155
188
  - Rakefile
156
189
  - lib/upsert.rb
190
+ - lib/upsert/binary.rb
157
191
  - lib/upsert/buffer.rb
158
192
  - lib/upsert/buffer/mysql2_client.rb
159
193
  - lib/upsert/buffer/pg_connection.rb
@@ -163,11 +197,16 @@ files:
163
197
  - lib/upsert/row.rb
164
198
  - lib/upsert/version.rb
165
199
  - test/helper.rb
166
- - test/shared_examples.rb
200
+ - test/shared/binary.rb
201
+ - test/shared/correctness.rb
202
+ - test/shared/database.rb
203
+ - test/shared/multibyte.rb
204
+ - test/shared/speed.rb
205
+ - test/shared/timezones.rb
206
+ - test/test_active_record_connection_adapter.rb
167
207
  - test/test_mysql2.rb
168
208
  - test/test_pg.rb
169
209
  - test/test_sqlite.rb
170
- - test/test_upsert.rb
171
210
  - upsert.gemspec
172
211
  homepage: https://github.com/seamusabshere/upsert
173
212
  licenses: []
@@ -196,9 +235,14 @@ summary: Upsert for MySQL, PostgreSQL, and SQLite. Finally, all those SQL MERGE
196
235
  codified.
197
236
  test_files:
198
237
  - test/helper.rb
199
- - test/shared_examples.rb
238
+ - test/shared/binary.rb
239
+ - test/shared/correctness.rb
240
+ - test/shared/database.rb
241
+ - test/shared/multibyte.rb
242
+ - test/shared/speed.rb
243
+ - test/shared/timezones.rb
244
+ - test/test_active_record_connection_adapter.rb
200
245
  - test/test_mysql2.rb
201
246
  - test/test_pg.rb
202
247
  - test/test_sqlite.rb
203
- - test/test_upsert.rb
204
248
  has_rdoc:
data/test/test_upsert.rb DELETED
@@ -1,7 +0,0 @@
1
- require 'helper'
2
-
3
- describe Upsert do
4
- describe :row do
5
-
6
- end
7
- end