ohm 1.0.0.rc1 → 1.0.0.rc2
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/README.md +1 -1
- data/Rakefile +1 -1
- data/lib/ohm.rb +99 -81
- data/lib/ohm/transaction.rb +21 -17
- data/test/association.rb +1 -1
- data/test/connection.rb +1 -1
- data/test/counters.rb +1 -1
- data/test/extensibility.rb +1 -1
- data/test/filtering.rb +19 -19
- data/test/helper.rb +1 -0
- data/test/indices.rb +5 -5
- data/test/json.rb +9 -9
- data/test/lua-save.rb +34 -34
- data/test/lua.rb +5 -5
- data/test/model.rb +16 -16
- data/test/pipeline-performance.rb +13 -11
- data/test/transactions.rb +32 -45
- data/test/uniques.rb +9 -9
- data/test/validations.rb +4 -4
- metadata +10 -10
data/lib/ohm/transaction.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "set"
|
2
|
-
|
3
1
|
module Ohm
|
4
2
|
|
5
3
|
# Transactions in Ohm are designed to be composable and atomic. They use
|
@@ -42,27 +40,27 @@ module Ohm
|
|
42
40
|
#
|
43
41
|
# @see http://redis.io/topic/transactions Transactions in Redis.
|
44
42
|
class Transaction
|
45
|
-
class Store
|
46
|
-
class EntryAlreadyExistsError <
|
43
|
+
class Store
|
44
|
+
class EntryAlreadyExistsError < RuntimeError
|
47
45
|
end
|
48
46
|
|
49
|
-
|
50
|
-
|
47
|
+
class NoEntryError < RuntimeError
|
48
|
+
end
|
51
49
|
|
52
|
-
|
50
|
+
def initialize
|
51
|
+
@dict = Hash.new
|
52
|
+
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
end
|
54
|
+
def [](key)
|
55
|
+
raise NoEntryError unless @dict.member?(key)
|
57
56
|
|
58
|
-
|
59
|
-
::Kernel.raise EntryAlreadyExistsError
|
60
|
-
end
|
57
|
+
@dict[key]
|
61
58
|
end
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
def []=(key, value)
|
61
|
+
raise EntryAlreadyExistsError if @dict.member?(key)
|
62
|
+
|
63
|
+
@dict[key] = value
|
66
64
|
end
|
67
65
|
end
|
68
66
|
|
@@ -83,7 +81,7 @@ module Ohm
|
|
83
81
|
end
|
84
82
|
|
85
83
|
def watch(*keys)
|
86
|
-
phase[:watch]
|
84
|
+
phase[:watch].concat(keys - phase[:watch])
|
87
85
|
end
|
88
86
|
|
89
87
|
def read(&block)
|
@@ -117,6 +115,8 @@ module Ohm
|
|
117
115
|
break if db.multi do
|
118
116
|
run(phase[:write], store)
|
119
117
|
end
|
118
|
+
|
119
|
+
store = nil
|
120
120
|
end
|
121
121
|
|
122
122
|
phase[:after].each(&:call)
|
@@ -126,4 +126,8 @@ module Ohm
|
|
126
126
|
procs.each { |p| p.call(store) }
|
127
127
|
end
|
128
128
|
end
|
129
|
+
|
130
|
+
def self.transaction(&block)
|
131
|
+
Transaction.new(&block)
|
132
|
+
end
|
129
133
|
end
|
data/test/association.rb
CHANGED
data/test/connection.rb
CHANGED
@@ -5,7 +5,7 @@ require File.expand_path("./helper", File.dirname(__FILE__))
|
|
5
5
|
prepare.clear
|
6
6
|
|
7
7
|
test "no rewriting of settings hash when using Ohm.connect" do
|
8
|
-
settings = { url
|
8
|
+
settings = { :url => "redis://127.0.0.1:6379/15" }.freeze
|
9
9
|
|
10
10
|
ex = nil
|
11
11
|
|
data/test/counters.rb
CHANGED
data/test/extensibility.rb
CHANGED
data/test/filtering.rb
CHANGED
@@ -10,51 +10,51 @@ class User < Ohm::Model
|
|
10
10
|
end
|
11
11
|
|
12
12
|
setup do
|
13
|
-
u1 = User.create(fname
|
14
|
-
u2 = User.create(fname
|
13
|
+
u1 = User.create(:fname => "John", :lname => "Doe", :status => "active")
|
14
|
+
u2 = User.create(:fname => "Jane", :lname => "Doe", :status => "active")
|
15
15
|
|
16
16
|
[u1, u2]
|
17
17
|
end
|
18
18
|
|
19
19
|
test "findability" do |john, jane|
|
20
|
-
assert_equal 1, User.find(lname
|
21
|
-
assert User.find(lname
|
20
|
+
assert_equal 1, User.find(:lname => "Doe", :fname => "John").size
|
21
|
+
assert User.find(:lname => "Doe", :fname => "John").include?(john)
|
22
22
|
|
23
|
-
assert_equal 1, User.find(lname
|
24
|
-
assert User.find(lname
|
23
|
+
assert_equal 1, User.find(:lname => "Doe", :fname => "Jane").size
|
24
|
+
assert User.find(:lname => "Doe", :fname => "Jane").include?(jane)
|
25
25
|
end
|
26
26
|
|
27
27
|
test "sets aren't mutable" do |john, jane|
|
28
28
|
assert_raise NoMethodError do
|
29
|
-
User.find(lname
|
29
|
+
User.find(:lname => "Doe").add(john)
|
30
30
|
end
|
31
31
|
|
32
32
|
assert_raise NoMethodError do
|
33
|
-
User.find(lname
|
33
|
+
User.find(:lname => "Doe", :fname => "John").add(john)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
test "#first" do |john, jane|
|
38
|
-
set = User.find(lname
|
38
|
+
set = User.find(:lname => "Doe", :status => "active")
|
39
39
|
|
40
|
-
assert_equal jane, set.first(by
|
41
|
-
assert_equal john, set.first(by
|
40
|
+
assert_equal jane, set.first(:by => "fname", :order => "ALPHA")
|
41
|
+
assert_equal john, set.first(:by => "fname", :order => "ALPHA DESC")
|
42
42
|
|
43
|
-
assert_equal "Jane", set.first(by
|
44
|
-
assert_equal "John", set.first(by
|
43
|
+
assert_equal "Jane", set.first(:by => "fname", :order => "ALPHA", :get => "fname")
|
44
|
+
assert_equal "John", set.first(:by => "fname", :order => "ALPHA DESC", :get => "fname")
|
45
45
|
end
|
46
46
|
|
47
47
|
test "#[]" do |john, jane|
|
48
|
-
set = User.find(lname
|
48
|
+
set = User.find(:lname => "Doe", :status => "active")
|
49
49
|
|
50
50
|
assert_equal john, set[john.id]
|
51
51
|
assert_equal jane, set[jane.id]
|
52
52
|
end
|
53
53
|
|
54
54
|
test "#except" do |john, jane|
|
55
|
-
out = User.create(status
|
55
|
+
out = User.create(:status => "inactive", :lname => "Doe")
|
56
56
|
|
57
|
-
res = User.find(lname
|
57
|
+
res = User.find(:lname => "Doe").except(:status => "inactive")
|
58
58
|
|
59
59
|
assert_equal 2, res.size
|
60
60
|
assert res.include?(john)
|
@@ -62,10 +62,10 @@ test "#except" do |john, jane|
|
|
62
62
|
end
|
63
63
|
|
64
64
|
test "#union" do |john, jane|
|
65
|
-
included = User.create(status
|
66
|
-
excluded = User.create(status
|
65
|
+
included = User.create(:status => "inactive", :lname => "Doe")
|
66
|
+
excluded = User.create(:status => "super", :lname => "Doe")
|
67
67
|
|
68
|
-
res = User.find(status
|
68
|
+
res = User.find(:status => "active").union(:status => "inactive")
|
69
69
|
|
70
70
|
assert_equal 3, res.size
|
71
71
|
assert res.include?(john)
|
data/test/helper.rb
CHANGED
data/test/indices.rb
CHANGED
@@ -27,13 +27,13 @@ class User < Ohm::Model
|
|
27
27
|
end
|
28
28
|
|
29
29
|
setup do
|
30
|
-
@user1 = User.create(email
|
31
|
-
@user2 = User.create(email
|
32
|
-
@user3 = User.create(email
|
30
|
+
@user1 = User.create(:email => "foo", :activation_code => "bar", :update => "baz")
|
31
|
+
@user2 = User.create(:email => "bar")
|
32
|
+
@user3 = User.create(:email => "baz qux")
|
33
33
|
end
|
34
34
|
|
35
35
|
test "be able to find by the given attribute" do
|
36
|
-
assert @user1 == User.find(email
|
36
|
+
assert @user1 == User.find(:email => "foo").first
|
37
37
|
end
|
38
38
|
|
39
39
|
test "raise an error if the parameter supplied is not a hash" do
|
@@ -47,7 +47,7 @@ test "raise an error if the parameter supplied is not a hash" do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
test "avoid intersections with the all collection" do
|
50
|
-
assert_equal "User:indices:email:foo", User.find(email
|
50
|
+
assert_equal "User:indices:email:foo", User.find(:email => "foo").key
|
51
51
|
end
|
52
52
|
|
53
53
|
test "cleanup the temporary key after use" do
|
data/test/json.rb
CHANGED
@@ -35,7 +35,7 @@ test "export a hash with the errors" do
|
|
35
35
|
person = Venue.new
|
36
36
|
person.valid?
|
37
37
|
|
38
|
-
assert_equal({ errors
|
38
|
+
assert_equal({ :errors => { :name => [:not_present] }}, person.to_hash)
|
39
39
|
end
|
40
40
|
|
41
41
|
test "export a hash with the its id" do
|
@@ -48,7 +48,7 @@ test "export a hash with its id and the errors" do
|
|
48
48
|
person.name = nil
|
49
49
|
person.valid?
|
50
50
|
|
51
|
-
expected_hash = { id
|
51
|
+
expected_hash = { :id => '1', :errors => { :name => [:not_present] }}
|
52
52
|
assert expected_hash == person.to_hash
|
53
53
|
end
|
54
54
|
|
@@ -68,19 +68,19 @@ test "just be the to_hash of a model" do
|
|
68
68
|
end
|
69
69
|
|
70
70
|
test "export an array of records to json" do
|
71
|
-
Programmer.create(language
|
72
|
-
Programmer.create(language
|
71
|
+
Programmer.create(:language => "Ruby")
|
72
|
+
Programmer.create(:language => "Python")
|
73
73
|
|
74
|
-
expected = [{ id
|
74
|
+
expected = [{ :id => "1", :language => "Ruby" }, { :id => "2", :language => "Python"}].to_json
|
75
75
|
assert_equal expected, Programmer.all.to_json
|
76
76
|
end
|
77
77
|
|
78
78
|
test "export an array of lists to json" do
|
79
|
-
venue = Venue.create(name
|
79
|
+
venue = Venue.create(:name => "Foo")
|
80
80
|
|
81
|
-
venue.programmers.push(Programmer.create(language
|
82
|
-
venue.programmers.push(Programmer.create(language
|
81
|
+
venue.programmers.push(Programmer.create(:language => "Ruby"))
|
82
|
+
venue.programmers.push(Programmer.create(:language => "Python"))
|
83
83
|
|
84
|
-
expected = [{ id
|
84
|
+
expected = [{ :id => "1", :language => "Ruby" }, { :id => "2", :language => "Python"}].to_json
|
85
85
|
assert_equal expected, venue.programmers.to_json
|
86
86
|
end
|
data/test/lua-save.rb
CHANGED
@@ -23,8 +23,8 @@ else
|
|
23
23
|
|
24
24
|
test "empty email doesn't choke" do |lua|
|
25
25
|
res = lua.run_file("save",
|
26
|
-
keys
|
27
|
-
argv
|
26
|
+
:keys => ["User"],
|
27
|
+
:argv => ["email", nil])
|
28
28
|
|
29
29
|
assert_equal [200, ["id", "1"]], res
|
30
30
|
assert_equal "1", redis.hget("User:uniques:email", nil)
|
@@ -32,8 +32,8 @@ else
|
|
32
32
|
|
33
33
|
test "empty fname / lname doesn't choke" do |lua|
|
34
34
|
res = lua.run_file("save",
|
35
|
-
keys
|
36
|
-
argv
|
35
|
+
:keys => ["User"],
|
36
|
+
:argv => ["email", nil, "fname", nil, "lname", nil])
|
37
37
|
|
38
38
|
assert_equal [200, ["id", "1"]], res
|
39
39
|
assert redis.sismember("User:indices:fname:", 1)
|
@@ -42,24 +42,24 @@ else
|
|
42
42
|
|
43
43
|
test "returns the unique constraint error" do |lua|
|
44
44
|
res = lua.run_file("save",
|
45
|
-
keys
|
46
|
-
argv
|
45
|
+
:keys => ["User"],
|
46
|
+
:argv => ["email", "foo@bar.com"])
|
47
47
|
|
48
48
|
assert_equal [500, ["email", "not_unique"]], res
|
49
49
|
end
|
50
50
|
|
51
51
|
test "persists the unique entry properly" do |lua|
|
52
52
|
lua.run_file("save",
|
53
|
-
keys
|
54
|
-
argv
|
53
|
+
:keys => ["User"],
|
54
|
+
:argv => ["email", "bar@baz.com"])
|
55
55
|
|
56
56
|
assert_equal "1", redis.hget("User:uniques:email", "bar@baz.com")
|
57
57
|
end
|
58
58
|
|
59
59
|
test "adds the entry to User:all" do |lua|
|
60
60
|
lua.run_file("save",
|
61
|
-
keys
|
62
|
-
argv
|
61
|
+
:keys => ["User"],
|
62
|
+
:argv => ["email", "bar@baz.com"])
|
63
63
|
|
64
64
|
assert_equal 1, redis.scard("User:all")
|
65
65
|
end
|
@@ -67,8 +67,8 @@ else
|
|
67
67
|
|
68
68
|
test "saves the attributes" do |lua|
|
69
69
|
lua.run_file("save",
|
70
|
-
keys
|
71
|
-
argv
|
70
|
+
:keys => ["User"],
|
71
|
+
:argv => ["email", "bar@baz.com", "fname", "John", "lname", "Doe"])
|
72
72
|
|
73
73
|
assert_equal "bar@baz.com", redis.hget("User:1", "email")
|
74
74
|
assert_equal "John", redis.hget("User:1", "fname")
|
@@ -77,8 +77,8 @@ else
|
|
77
77
|
|
78
78
|
test "indexes fname / lname" do |lua|
|
79
79
|
lua.run_file("save",
|
80
|
-
keys
|
81
|
-
argv
|
80
|
+
:keys => ["User"],
|
81
|
+
:argv => ["email", "bar@baz.com", "fname", "John", "lname", "Doe"])
|
82
82
|
|
83
83
|
assert redis.sismember("User:indices:fname:John", 1)
|
84
84
|
assert redis.sismember("User:indices:lname:Doe", 1)
|
@@ -86,30 +86,30 @@ else
|
|
86
86
|
|
87
87
|
test "unique constraint during update" do |lua|
|
88
88
|
lua.run_file("save",
|
89
|
-
keys
|
90
|
-
argv
|
89
|
+
:keys => ["User"],
|
90
|
+
:argv => ["email", "bar@baz.com", "fname", "John", "lname", "Doe"])
|
91
91
|
|
92
92
|
res = lua.run_file("save",
|
93
|
-
keys
|
94
|
-
argv
|
93
|
+
:keys => ["User", "User:1"],
|
94
|
+
:argv => ["email", "bar@baz.com", "fname", "John", "lname", "Doe"])
|
95
95
|
|
96
96
|
assert_equal [200, ["id", "1"]], res
|
97
97
|
|
98
98
|
res = lua.run_file("save",
|
99
|
-
keys
|
100
|
-
argv
|
99
|
+
:keys => ["User", "User:1"],
|
100
|
+
:argv => ["email", "foo@bar.com", "fname", "Jane", "lname", "Doe"])
|
101
101
|
|
102
102
|
assert_equal [200, ["id", "1"]], res
|
103
103
|
end
|
104
104
|
|
105
105
|
test "cleanup of existing indices during update" do |lua|
|
106
106
|
lua.run_file("save",
|
107
|
-
keys
|
108
|
-
argv
|
107
|
+
:keys => ["User"],
|
108
|
+
:argv => ["email", "bar@baz.com", "fname", "John", "lname", "Doe"])
|
109
109
|
|
110
110
|
res = lua.run_file("save",
|
111
|
-
keys
|
112
|
-
argv
|
111
|
+
:keys => ["User", "User:1"],
|
112
|
+
:argv => ["email", "foo@bar.com", "fname", "Jane", "lname", "Smith"])
|
113
113
|
|
114
114
|
assert ! redis.sismember("User:indices:fname:John", 1)
|
115
115
|
assert ! redis.sismember("User:indices:fname:Doe", 1)
|
@@ -117,12 +117,12 @@ else
|
|
117
117
|
|
118
118
|
test "cleanup of existing uniques during update" do |lua|
|
119
119
|
lua.run_file("save",
|
120
|
-
keys
|
121
|
-
argv
|
120
|
+
:keys => ["User"],
|
121
|
+
:argv => ["email", "bar@baz.com", "fname", "John", "lname", "Doe"])
|
122
122
|
|
123
123
|
res = lua.run_file("save",
|
124
|
-
keys
|
125
|
-
argv
|
124
|
+
:keys => ["User", "User:1"],
|
125
|
+
:argv => ["email", "foo@bar.com", "fname", "Jane", "lname", "Smith"])
|
126
126
|
|
127
127
|
assert_equal nil, redis.hget("User:uniques:email", "bar@baz.com")
|
128
128
|
end
|
@@ -147,9 +147,9 @@ test "stress test for lua scripting" do |lua|
|
|
147
147
|
t = Benchmark.measure do
|
148
148
|
threads = 100.times.map do |i|
|
149
149
|
Thread.new do
|
150
|
-
User.create(email
|
151
|
-
fname
|
152
|
-
lname
|
150
|
+
User.create(:email => "foo#{i}@bar.com",
|
151
|
+
:fname => "Jane#{i}",
|
152
|
+
:lname => "Smith#{i}")
|
153
153
|
end
|
154
154
|
end
|
155
155
|
|
@@ -167,9 +167,9 @@ test "stress test for postgres + sequel (as a comparison)" do
|
|
167
167
|
t = Benchmark.measure do
|
168
168
|
threads = 100.times.map do |i|
|
169
169
|
Thread.new do
|
170
|
-
DB[:users].insert(email
|
171
|
-
fname
|
172
|
-
lname
|
170
|
+
DB[:users].insert(:email => "foo#{i}@bar.com",
|
171
|
+
:fname => "John#{i}",
|
172
|
+
:lname => "Doe#{i}")
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
data/test/lua.rb
CHANGED
@@ -15,14 +15,14 @@ else
|
|
15
15
|
test do |lua|
|
16
16
|
lua.redis.set("foo", "baz")
|
17
17
|
|
18
|
-
res = lua.run_file("getset", keys
|
18
|
+
res = lua.run_file("getset", :keys => ["foo"], :argv => ["bar"])
|
19
19
|
assert_equal ["baz", "bar"], res
|
20
20
|
end
|
21
21
|
|
22
22
|
test do |lua|
|
23
23
|
res = lua.run_file("ohm-save",
|
24
|
-
keys
|
25
|
-
argv
|
24
|
+
:keys => ["User"],
|
25
|
+
:argv => ["fname", "John", "lname", "Doe"])
|
26
26
|
|
27
27
|
assert lua.redis.sismember("User:all", 1)
|
28
28
|
assert_equal({ "fname" => "John", "lname" => "Doe" },
|
@@ -34,8 +34,8 @@ else
|
|
34
34
|
lua.redis.sadd("User:indices", "lname")
|
35
35
|
|
36
36
|
res = lua.run_file("save-with-indices",
|
37
|
-
keys
|
38
|
-
argv
|
37
|
+
:keys => ["User:1", "User:all", "User:indices"],
|
38
|
+
:argv => ["fname", "John", "lname", "Doe"])
|
39
39
|
|
40
40
|
assert lua.redis.sismember("User:all", 1)
|
41
41
|
|