upsert 2.0.4 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e403ffd510814ad862057a3059f8ce8e65d974d4
4
- data.tar.gz: 142ba5495b4d63641f23b1e54ab2c855a9f858d9
3
+ metadata.gz: 8a8d49c15022e8faa065c2f060349210b28998b9
4
+ data.tar.gz: 3814d296ef548257347af887ca39a04b801ceb91
5
5
  SHA512:
6
- metadata.gz: d4ad43d341e5fefbecac30c296f4dc6956e4e513a68e1aca95ea0026017ce882849b59144282cc9ac82f7eabea5bfc9297a134b7f3b6320b9ad717be180d977d
7
- data.tar.gz: 3bec3b12605a00058fb654d718baa5cc6adef91ea8e1b6931e22248a3f45f1a3652db43183923346516675edf4ff0269d3a0122199ac941784851c996d6f0583
6
+ metadata.gz: e3a2553e8a0d143bb90592d1dc7f5a4ccd9224386fdce394dceef2ad2f46e186a853e61560ef1d6ea93f52b5bb7e948659c62398c60cc6c5d8c5887bdd9c6d0f
7
+ data.tar.gz: 864fcc5434d104ae1c4d5e8d68a8e8546217612be2d710b01a8ecfbd5e25435f2181a8c59afd7f6224b388762276f93256be6c7cec4ea5e18e994129ba1b396d
@@ -3,9 +3,13 @@ global:
3
3
  - USERNAME=travis
4
4
  PASSWORD=
5
5
  rvm:
6
+ - 2.2.0
7
+ - 2.1.0
8
+ - 2.0.0
6
9
  - 1.9.3
7
10
  - 1.9.2
8
11
  - 1.8.7
12
+ - rbx-2
9
13
  env:
10
14
  - DB=postgresql
11
15
  - DB=mysql
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ 2.1.0 / 2015-03-13
2
+
3
+ * Bug fixes
4
+
5
+ * Thread safety with Sidekiq! thanks @evadne and @thbar ! https://github.com/seamusabshere/upsert/pull/47
6
+
7
+ * Known issues
8
+
9
+ * speed_spec fails against activerecord-import on mysql... need some advice on properly testing it
10
+
1
11
  2.0.4 / 2015-01-27
2
12
 
3
13
  * Bug fixes
data/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # Upsert
2
2
 
3
- **note** There is a known problem with mysql2 and sidekiq - we're working on it in https://github.com/seamusabshere/upsert/tree/real_thread_safe and various issues
4
-
5
3
  [![Build Status](https://travis-ci.org/seamusabshere/upsert.svg?branch=master)](https://travis-ci.org/seamusabshere/upsert)
6
4
 
7
5
  Make it easy to upsert on traditional RDBMS like MySQL, PostgreSQL, and SQLite3—hey look NoSQL!. Transparently creates (and re-uses) stored procedures/functions when necessary.
@@ -157,7 +155,7 @@ From the tests (updated 11/7/12):
157
155
  Upsert was 82% faster than find + new/set/save
158
156
  Upsert was 85% faster than find_or_create + update_attributes
159
157
  Upsert was 90% faster than create + rescue/find/update
160
- Upsert was 46% faster than faking upserts with activerecord-import
158
+ Upsert was 46% faster than faking upserts with activerecord-import (note: in question as of 3/13/15, need some expert advice)
161
159
 
162
160
  #### SQL MERGE trick
163
161
 
@@ -194,6 +194,7 @@ class Upsert
194
194
  end
195
195
  @connection = Connection.const_get(adapter).new self, metal
196
196
  @merge_function_class = MergeFunction.const_get adapter
197
+ @merge_function_cache = {}
197
198
  @assume_function_exists = options.fetch :assume_function_exists, false
198
199
  end
199
200
 
@@ -213,7 +214,8 @@ class Upsert
213
214
  # upsert.row({:name => 'Jerry'}, :breed => 'beagle')
214
215
  # upsert.row({:name => 'Pierre'}, :breed => 'tabby')
215
216
  def row(selector, setter = {}, options = nil)
216
- merge_function_class.execute self, Row.new(selector, setter, options)
217
+ row_object = Row.new(selector, setter, options)
218
+ merge_function(row_object).execute(row_object)
217
219
  nil
218
220
  end
219
221
 
@@ -221,6 +223,11 @@ class Upsert
221
223
  def clear_database_functions
222
224
  merge_function_class.clear connection
223
225
  end
226
+
227
+ def merge_function(row)
228
+ cache_key = [row.selector.keys, row.setter.keys]
229
+ @merge_function_cache[cache_key] ||= merge_function_class.new(self, row.selector.keys, row.setter.keys, assume_function_exists?)
230
+ end
224
231
 
225
232
  # @private
226
233
  def quoted_table_name
@@ -8,11 +8,6 @@ class Upsert
8
8
  NAME_PREFIX = "upsert#{Upsert::VERSION.gsub('.', '_')}"
9
9
 
10
10
  class << self
11
- def execute(controller, row)
12
- merge_function = lookup controller, row
13
- merge_function.execute row
14
- end
15
-
16
11
  def unique_name(table_name, selector_keys, setter_keys)
17
12
  parts = [
18
13
  NAME_PREFIX,
@@ -30,14 +25,6 @@ class Upsert
30
25
  parts
31
26
  end
32
27
  end
33
-
34
- def lookup(controller, row)
35
- @lookup ||= {}
36
- selector_keys = row.selector.keys
37
- setter_keys = row.setter.keys
38
- key = [controller.table_name, selector_keys, setter_keys]
39
- @lookup[key] ||= new(controller, selector_keys, setter_keys, controller.assume_function_exists?)
40
- end
41
28
  end
42
29
 
43
30
  attr_reader :controller
@@ -53,7 +40,7 @@ class Upsert
53
40
  end
54
41
 
55
42
  def name
56
- @name ||= MergeFunction.unique_name table_name, selector_keys, setter_keys
43
+ @name ||= self.class.unique_name table_name, selector_keys, setter_keys
57
44
  end
58
45
 
59
46
  def connection
@@ -1,3 +1,3 @@
1
1
  class Upsert
2
- VERSION = '2.0.4'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -2,27 +2,43 @@ require 'spec_helper'
2
2
  require 'stringio'
3
3
  describe Upsert do
4
4
  describe 'database functions' do
5
-
6
- it "re-uses merge functions across connections" do
5
+ it "does not re-use merge functions across connections" do
7
6
  begin
8
7
  io = StringIO.new
9
8
  old_logger = Upsert.logger
10
9
  Upsert.logger = Logger.new io, Logger::INFO
11
10
 
12
- # clear
11
+ # clear, create (#1)
13
12
  Upsert.clear_database_functions($conn_factory.new_connection)
14
-
15
- # create
16
13
  Upsert.new($conn_factory.new_connection, :pets).row :name => 'hello'
17
14
 
18
- # clear
15
+ # clear, create (#2)
19
16
  Upsert.clear_database_functions($conn_factory.new_connection)
20
-
21
- # create (#2)
22
17
  Upsert.new($conn_factory.new_connection, :pets).row :name => 'hello'
18
+
19
+ io.rewind
20
+ hits = io.read.split("\n").grep(/Creating or replacing/)
21
+ hits.length.should == 2
22
+ ensure
23
+ Upsert.logger = old_logger
24
+ end
25
+ end
26
+
27
+ it "does not re-use merge functions even when on the same connection" do
28
+ begin
29
+ io = StringIO.new
30
+ old_logger = Upsert.logger
31
+ Upsert.logger = Logger.new io, Logger::INFO
32
+
33
+ connection = $conn_factory.new_connection
23
34
 
24
- # no create!
25
- Upsert.new($conn_factory.new_connection, :pets).row :name => 'hello'
35
+ # clear, create (#1)
36
+ Upsert.clear_database_functions(connection)
37
+ Upsert.new(connection, :pets).row :name => 'hello'
38
+
39
+ # clear, create (#2)
40
+ Upsert.clear_database_functions(connection)
41
+ Upsert.new(connection, :pets).row :name => 'hello'
26
42
 
27
43
  io.rewind
28
44
  hits = io.read.split("\n").grep(/Creating or replacing/)
@@ -31,6 +47,29 @@ describe Upsert do
31
47
  Upsert.logger = old_logger
32
48
  end
33
49
  end
50
+
51
+ it "re-uses merge functions within batch" do
52
+ begin
53
+ io = StringIO.new
54
+ old_logger = Upsert.logger
55
+ Upsert.logger = Logger.new io, Logger::INFO
56
+
57
+ # clear
58
+ Upsert.clear_database_functions($conn_factory.new_connection)
59
+
60
+ # create
61
+ Upsert.batch($conn_factory.new_connection, :pets) do |upsert|
62
+ upsert.row :name => 'hello'
63
+ upsert.row :name => 'world'
64
+ end
65
+
66
+ io.rewind
67
+ hits = io.read.split("\n").grep(/Creating or replacing/)
68
+ hits.length.should == 1
69
+ ensure
70
+ Upsert.logger = old_logger
71
+ end
72
+ end
34
73
 
35
74
  it "assumes function exists if told to" do
36
75
  begin
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: upsert
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seamus Abshere
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-27 00:00:00.000000000 Z
11
+ date: 2015-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-core