ohm 1.0.0.rc1 → 1.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|