ohm 2.0.0.rc1 → 2.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gems +3 -3
- data/CHANGELOG.md +293 -0
- data/README.md +1 -1
- data/benchmarks/common.rb +1 -1
- data/examples/json-hash.rb +17 -44
- data/lib/ohm.rb +112 -27
- data/lib/ohm/lua/save.lua +1 -1
- data/ohm.gemspec +1 -1
- data/test/association.rb +1 -1
- data/test/connection.rb +5 -11
- data/test/core.rb +8 -10
- data/test/counters.rb +1 -1
- data/test/enumerable.rb +2 -2
- data/test/filtering.rb +2 -2
- data/test/hash_key.rb +1 -3
- data/test/helper.rb +1 -5
- data/test/indices.rb +1 -3
- data/test/json.rb +1 -2
- data/test/list.rb +15 -1
- data/test/model.rb +9 -19
- data/test/set.rb +17 -0
- data/test/thread_safety.rb +67 -0
- data/test/uniques.rb +1 -3
- metadata +4 -4
- data/CHANGELOG +0 -112
- data/test/issue-52.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44f992bf97d394e618f9e3608a13999e6a37ffbf
|
4
|
+
data.tar.gz: 9e97ba2177d8067c64ab4e2b0b7a0a710703bb18
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0d5bc81d2fa070ee3b9306844bc61a1d089cf67e464fd8c3939274db918d986f3e6d97c8166ae3f1caf2c0d679c7c1802c55499d65dc0ca35a619ee9446b342
|
7
|
+
data.tar.gz: 50008d8d644b1825507db45e921e78aaa0cd19b48fc587eca43605495155d91e816e49abc75a02f6bc4aef1e5351c81940384da4eb97c8e3e8eb6934ba75ce65
|
data/.gems
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,293 @@
|
|
1
|
+
- Lists now respond to range.
|
2
|
+
|
3
|
+
Example:
|
4
|
+
|
5
|
+
class Comment < Ohm::Model
|
6
|
+
end
|
7
|
+
|
8
|
+
class Post < Ohm::Model
|
9
|
+
list :comments, :Comment
|
10
|
+
end
|
11
|
+
|
12
|
+
c1 = Comment.create
|
13
|
+
c2 = Comment.create
|
14
|
+
c3 = Comment.create
|
15
|
+
|
16
|
+
post = Post.create
|
17
|
+
post.comments.push(c1)
|
18
|
+
post.comments.push(c2)
|
19
|
+
post.comments.push(c3)
|
20
|
+
|
21
|
+
post.comments.range(0, 1) == [c1, c2]
|
22
|
+
# => true
|
23
|
+
|
24
|
+
- When a record is created, `#id` returns a string instead of a integer.
|
25
|
+
This ensures ID is string everywhere:
|
26
|
+
|
27
|
+
Example:
|
28
|
+
|
29
|
+
## Before
|
30
|
+
|
31
|
+
Meetup.create(name: "Ruby").id
|
32
|
+
# => 1
|
33
|
+
|
34
|
+
Meetup.find(name: "Ruby").id
|
35
|
+
# => "1"
|
36
|
+
|
37
|
+
## Now
|
38
|
+
|
39
|
+
Meetup.create.id
|
40
|
+
# => "1"
|
41
|
+
|
42
|
+
Meetup.find(name: "Ruby").id
|
43
|
+
# => "1"
|
44
|
+
|
45
|
+
- If an attribute is set to an empty string, Ohm won't delete the attribute.
|
46
|
+
|
47
|
+
Example:
|
48
|
+
|
49
|
+
# Before
|
50
|
+
event = Meetup.create(location: "")
|
51
|
+
Meetup[event.id].location
|
52
|
+
# => nil
|
53
|
+
|
54
|
+
# Now
|
55
|
+
event = Meetup.create(location: "")
|
56
|
+
Meetup[event.id].location
|
57
|
+
# => ""
|
58
|
+
|
59
|
+
- Include `Ohm::List#ids` in the public API. It returns an array with all
|
60
|
+
the ID's of the list.
|
61
|
+
|
62
|
+
Example:
|
63
|
+
|
64
|
+
class Comment < Ohm::Model
|
65
|
+
end
|
66
|
+
|
67
|
+
class Post < Ohm::Model
|
68
|
+
list :comments, :Comment
|
69
|
+
end
|
70
|
+
|
71
|
+
post = Post.create
|
72
|
+
post.comments.push(Comment.create)
|
73
|
+
post.comments.push(Comment.create)
|
74
|
+
post.comments.push(Comment.create)
|
75
|
+
|
76
|
+
post.comments.ids
|
77
|
+
# => ["1", "2", "3"]
|
78
|
+
|
79
|
+
- Include `Ohm::BasicSet#exists?` in the public API. This makes possible
|
80
|
+
to check if an id is included in a set. Check `Ohm::BasicSet#exists?`
|
81
|
+
documentation for more details.
|
82
|
+
|
83
|
+
Example:
|
84
|
+
|
85
|
+
class Post < Ohm::Model
|
86
|
+
end
|
87
|
+
|
88
|
+
class User < Ohm::Model
|
89
|
+
set :posts, :Post
|
90
|
+
end
|
91
|
+
|
92
|
+
user = User.create
|
93
|
+
user.posts.add(post = Post.create)
|
94
|
+
|
95
|
+
user.posts.exists?(post.id) # => true
|
96
|
+
user.posts.exists?("nonexistent") # => false
|
97
|
+
|
98
|
+
|
99
|
+
- Change `Ohm::MultiSet#except` to union keys instead of intersect them
|
100
|
+
when passing an array.
|
101
|
+
|
102
|
+
Example:
|
103
|
+
|
104
|
+
class User < Ohm::Model
|
105
|
+
attribute :name
|
106
|
+
end
|
107
|
+
|
108
|
+
john = User.create(name: "John")
|
109
|
+
jane = User.create(name: "Jane")
|
110
|
+
|
111
|
+
res = User.all.except(name: [john.name, jane.name])
|
112
|
+
|
113
|
+
# before
|
114
|
+
res.size # => 2
|
115
|
+
|
116
|
+
# now
|
117
|
+
res.size # => 0
|
118
|
+
|
119
|
+
|
120
|
+
- Move ID generation to Lua. With this change, it's no longer possible
|
121
|
+
to generate custom ids. All ids are autoincremented.
|
122
|
+
|
123
|
+
|
124
|
+
- Add `Ohm::Model.track` method to allow track of custom keys. This key
|
125
|
+
is removed when the model is deleted.
|
126
|
+
|
127
|
+
Example:
|
128
|
+
|
129
|
+
class Foo < Ohm::Model
|
130
|
+
track :notes
|
131
|
+
end
|
132
|
+
|
133
|
+
foo = Foo.create
|
134
|
+
|
135
|
+
Foo.redis.call("SET", foo.key[:notes], "something")
|
136
|
+
Foo.redis.call("KEYS", "*").include?("Foo:1:notes")
|
137
|
+
# => true
|
138
|
+
|
139
|
+
foo.delete
|
140
|
+
Foo.redis.call("KEYS", "*").include?("Foo:1:notes")
|
141
|
+
# => false
|
142
|
+
|
143
|
+
|
144
|
+
- `Ohm::Model#reference` accepts strings as model references.
|
145
|
+
|
146
|
+
Example:
|
147
|
+
|
148
|
+
class Bar < Ohm::Model
|
149
|
+
reference :foo, "SomeNamespace::Foo"
|
150
|
+
end
|
151
|
+
|
152
|
+
Bar.create().foo.class # => SomeNamespace::Foo
|
153
|
+
|
154
|
+
|
155
|
+
- `Ohm::Model#save` sanitizes attributes before sending to Lua.
|
156
|
+
This complies with the original spec in Ohm v1 where a `to_s`
|
157
|
+
is done on each value.
|
158
|
+
|
159
|
+
Example:
|
160
|
+
|
161
|
+
class Post < Ohm::Model
|
162
|
+
attribute :published
|
163
|
+
end
|
164
|
+
|
165
|
+
post = Post.create(published: true)
|
166
|
+
post = Post[post.id]
|
167
|
+
|
168
|
+
# before
|
169
|
+
post.published # => "1"
|
170
|
+
|
171
|
+
# now
|
172
|
+
post.published # => "true"
|
173
|
+
|
174
|
+
|
175
|
+
- `Ohm::Model#save` don't save values for attributes set to false.
|
176
|
+
|
177
|
+
Example:
|
178
|
+
|
179
|
+
class Post < Ohm::Model
|
180
|
+
attribute :published
|
181
|
+
end
|
182
|
+
|
183
|
+
post = Post.create(published: false)
|
184
|
+
post = Post[post.id]
|
185
|
+
|
186
|
+
# before
|
187
|
+
post.published # => "0"
|
188
|
+
|
189
|
+
# now
|
190
|
+
post.published # => nil
|
191
|
+
|
192
|
+
|
193
|
+
- `nest` dependency has been removed. Now, Ohm uses [nido][nido]
|
194
|
+
to generate the keys that hold the data.
|
195
|
+
|
196
|
+
|
197
|
+
- `scrivener` dependency has been removed. Ohm no longer supports model
|
198
|
+
validations and favors filter validation on the boundary layer. Check
|
199
|
+
[scrivener][scrivener] project for more information.
|
200
|
+
|
201
|
+
|
202
|
+
- `redis` dependency has been removed. Ohm 2 uses [redic][redic],
|
203
|
+
a lightweight Redis client. Redic uses the `hiredis` gem for the
|
204
|
+
connection and for parsing the replies. Now, it defaults to a
|
205
|
+
Redic connection to "redis://127.0.0.1:6379". To change it, you
|
206
|
+
will need to provide an instance of `Redic` through the `Ohm.redis=`
|
207
|
+
helper.
|
208
|
+
|
209
|
+
Example:
|
210
|
+
|
211
|
+
Ohm.redis = Redic.new("redis://:<passwd>@<host>:<port>/<db>")
|
212
|
+
|
213
|
+
Check Redic README for more details.
|
214
|
+
|
215
|
+
|
216
|
+
- `Ohm::Model#transaction` and `Ohm::Transaction` have been removed.
|
217
|
+
|
218
|
+
|
219
|
+
- Move `save` and `delete` operations to Lua scripts.
|
220
|
+
|
221
|
+
|
222
|
+
- Support for Ruby 1.8 and 1.9 has been removed.
|
223
|
+
|
224
|
+
[nido]: https://github.com/soveran/nido
|
225
|
+
[scrivener]: https://github.com/soveran/scrivener
|
226
|
+
[redic]: https://github.com/amakawa/redic
|
227
|
+
|
228
|
+
1.3.2
|
229
|
+
-----
|
230
|
+
|
231
|
+
- Fetching a batch of objects is now done in batches of 1000 objects at
|
232
|
+
a time. If you are iterating over large collections, this change should
|
233
|
+
provide a significant performance boost both in used memory and total
|
234
|
+
execution time.
|
235
|
+
- MutableSet#<< is now an alias for #add.
|
236
|
+
|
237
|
+
1.3.1
|
238
|
+
-----
|
239
|
+
|
240
|
+
- Improve memory consumption when indexing persisted attributes.
|
241
|
+
|
242
|
+
No migration is needed and old indices will be cleaned up as you save
|
243
|
+
instances.
|
244
|
+
|
245
|
+
1.3.0
|
246
|
+
-----
|
247
|
+
|
248
|
+
- Add Model.attributes.
|
249
|
+
|
250
|
+
1.2.0
|
251
|
+
-----
|
252
|
+
|
253
|
+
- Enumerable fix.
|
254
|
+
- Merge Ohm::PipelinedFetch into Ohm::Collection.
|
255
|
+
- Fix Set, MultiSet, and List enumerable behavior.
|
256
|
+
- Change dependencies to use latest cutest.
|
257
|
+
|
258
|
+
1.1.0
|
259
|
+
-----
|
260
|
+
|
261
|
+
- Compatible with redis-rb 3.
|
262
|
+
|
263
|
+
1.0.0
|
264
|
+
-----
|
265
|
+
|
266
|
+
- Fetching a batch of objects is now done through one pipeline, effectively
|
267
|
+
reducing the IO to just 2 operations (one for SMEMBERS / LRANGE, one for
|
268
|
+
the actual HGET of all the individual HASHes.)
|
269
|
+
- write_remote / read_remote have been replaced with set / get respectively.
|
270
|
+
- Ohm::Model.unique has been added.
|
271
|
+
- Ohm::Model::Set has been renamed to Ohm::Set
|
272
|
+
- Ohm::Model::List has been renamed to Ohm::List
|
273
|
+
- Ohm::Model::Collection is gone.
|
274
|
+
- Ohm::Validations is gone. Ohm now uses Scrivener::Validations.
|
275
|
+
- Ohm::Key is gone. Ohm now uses Nest directly.
|
276
|
+
- No more concept of volatile keys.
|
277
|
+
- Ohm::Model::Wrapper is gone.
|
278
|
+
- Use Symbols for constants instead of relying on Ohm::Model.const_missing.
|
279
|
+
- #sort / #sort_by now uses `limit` as it's used in redis-rb, e.g. you
|
280
|
+
have to pass in an array like so: sort(limit: [0, 1]).
|
281
|
+
- Set / List have been trimmed to contain only the minimum number
|
282
|
+
of necessary methods.
|
283
|
+
- You can no longer mutate a collection / set as before, e.g. doing
|
284
|
+
User.find(...).add(User[1]) will throw an error.
|
285
|
+
- The #union operation has been added. You can now chain it with your filters.
|
286
|
+
- Temporary keys when doing finds are now automatically cleaned up.
|
287
|
+
- Counters are now stored in their own key instead, i.e. in
|
288
|
+
User:<id>:counters.
|
289
|
+
- JSON support has to be explicitly required by doing `require
|
290
|
+
"ohm/json"`.
|
291
|
+
- All save / delete / update operations are now done using
|
292
|
+
transactions (see http://redis.io/topics/transactions).
|
293
|
+
- All indices are now stored without converting the values to base64.
|
data/README.md
CHANGED
data/benchmarks/common.rb
CHANGED
data/examples/json-hash.rb
CHANGED
@@ -5,91 +5,64 @@
|
|
5
5
|
# If you've ever needed to build an AJAX route handler, you may have noticed
|
6
6
|
# the prevalence of the design pattern where you return a JSON response.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# comment.to_json
|
8
|
+
# on get, "comments" do
|
9
|
+
# res.write Comment.all.to_json
|
11
10
|
# end
|
12
11
|
#
|
13
12
|
# `Ohm` helps you here by providing sensible defaults. It's not very popular,
|
14
13
|
# but `Ohm` actually has a `to_hash` method.
|
15
14
|
|
16
|
-
# Let's start by requiring `ohm` and `json`.
|
17
|
-
# actually part of the standard library, so you don't have to install a gem
|
18
|
-
# for it. For ruby 1.8.x, a simple `[sudo] gem install json` will do it.
|
15
|
+
# Let's start by requiring `ohm` and `ohm/json`.
|
19
16
|
require "ohm"
|
20
|
-
require "json"
|
17
|
+
require "ohm/json"
|
21
18
|
|
22
|
-
# Here we define our `Post` model with just a single `attribute` called
|
23
|
-
# `title`.
|
24
|
-
#
|
25
|
-
# We also define a validation, asserting the presence of the `title`.
|
19
|
+
# Here we define our `Post` model with just a single `attribute` called `title`.
|
26
20
|
class Post < Ohm::Model
|
27
21
|
attribute :title
|
28
|
-
|
29
|
-
def validate
|
30
|
-
assert_present :title
|
31
|
-
end
|
32
22
|
end
|
33
23
|
|
34
|
-
# Now let's load the test framework `cutest` to
|
35
|
-
# also call `Ohm.flush` for each test run.
|
24
|
+
# Now let's load the test framework `cutest` to test our code.
|
36
25
|
require "cutest"
|
37
26
|
|
27
|
+
# We also call `Ohm.flush` for each test run.
|
38
28
|
prepare { Ohm.flush }
|
39
29
|
|
40
30
|
# When we successfully create a `Post`, we can see that it returns
|
41
31
|
# only the *id* and its value in the hash.
|
42
32
|
test "hash representation when created" do
|
43
|
-
post = Post.create(:
|
33
|
+
post = Post.create(title: "my post")
|
44
34
|
|
45
|
-
|
35
|
+
assert_equal Hash[id: post.id], post.to_hash
|
46
36
|
end
|
47
37
|
|
48
38
|
# The JSON representation is actually just `post.to_hash.to_json`, so the
|
49
39
|
# same result, only in JSON, is returned.
|
50
40
|
test "json representation when created" do
|
51
|
-
post = Post.create(:
|
52
|
-
|
53
|
-
assert("{\"id\":\"1\"}" == post.to_json)
|
54
|
-
end
|
41
|
+
post = Post.create(title: "my post")
|
55
42
|
|
56
|
-
#
|
57
|
-
# an invalid `Post`. We can see that it returns the `errors` of the
|
58
|
-
# `Post`, because we added an `assert_present :title` in our code above.
|
59
|
-
test "hash representation when validation failed" do
|
60
|
-
post = Post.create
|
61
|
-
|
62
|
-
assert({ :errors => [[:title, :not_present]]} == post.to_hash)
|
63
|
-
end
|
64
|
-
|
65
|
-
# As is the case for a valid record, the JSON representation is
|
66
|
-
# still equivalent to `post.to_hash.to_json`.
|
67
|
-
test "json representation when validation failed" do
|
68
|
-
post = Post.create
|
69
|
-
|
70
|
-
assert("{\"errors\":[[\"title\",\"not_present\"]]}" == post.to_json)
|
43
|
+
assert_equal "{\"id\":\"#{post.id}\"}", post.to_json
|
71
44
|
end
|
72
45
|
|
73
46
|
#### Whitelisted approach
|
74
47
|
|
75
|
-
# Unlike
|
48
|
+
# Unlike other frameworks which dumps out all attributes by default,
|
76
49
|
# `Ohm` favors a whitelisted approach where you have to explicitly
|
77
50
|
# declare which attributes you want.
|
78
51
|
#
|
79
|
-
# By default, only `:id`
|
80
|
-
# it was successfully saved or if there were validation errors.
|
52
|
+
# By default, only `:id` will be available if the model is persisted.
|
81
53
|
|
82
54
|
# Let's re-open our Post class, and add a `to_hash` method.
|
83
55
|
class Post
|
84
56
|
def to_hash
|
85
|
-
super.merge(:
|
57
|
+
super.merge(title: title)
|
86
58
|
end
|
87
59
|
end
|
88
60
|
|
89
61
|
# Now, let's test that the title is in fact part of `to_hash`.
|
90
62
|
test "customized to_hash" do
|
91
|
-
post = Post.create(:
|
92
|
-
|
63
|
+
post = Post.create(title: "Override FTW?")
|
64
|
+
|
65
|
+
assert_equal Hash[id: post.id, title: post.title], post.to_hash
|
93
66
|
end
|
94
67
|
|
95
68
|
#### Conclusion
|
data/lib/ohm.rb
CHANGED
@@ -4,7 +4,7 @@ require "msgpack"
|
|
4
4
|
require "nido"
|
5
5
|
require "redic"
|
6
6
|
require "securerandom"
|
7
|
-
|
7
|
+
require_relative "ohm/command"
|
8
8
|
|
9
9
|
module Ohm
|
10
10
|
LUA_CACHE = Hash.new { |h, k| h[k] = Hash.new }
|
@@ -134,11 +134,15 @@ module Ohm
|
|
134
134
|
|
135
135
|
# Wraps the whole pipelining functionality.
|
136
136
|
def fetch(ids)
|
137
|
-
|
138
|
-
|
139
|
-
|
137
|
+
data = nil
|
138
|
+
|
139
|
+
model.synchronize do
|
140
|
+
ids.each do |id|
|
141
|
+
redis.queue("HGETALL", namespace[id])
|
142
|
+
end
|
140
143
|
|
141
|
-
|
144
|
+
data = redis.commit
|
145
|
+
end
|
142
146
|
|
143
147
|
return [] if data.nil?
|
144
148
|
|
@@ -178,6 +182,34 @@ module Ohm
|
|
178
182
|
model[redis.call("LINDEX", key, -1)]
|
179
183
|
end
|
180
184
|
|
185
|
+
# Returns an array of elements from the list using LRANGE.
|
186
|
+
# #range receives 2 integers, start and stop
|
187
|
+
#
|
188
|
+
# Example:
|
189
|
+
#
|
190
|
+
# class Comment < Ohm::Model
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
# class Post < Ohm::Model
|
194
|
+
# list :comments, :Comment
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# c1 = Comment.create
|
198
|
+
# c2 = Comment.create
|
199
|
+
# c3 = Comment.create
|
200
|
+
#
|
201
|
+
# post = Post.create
|
202
|
+
#
|
203
|
+
# post.comments.push(c1)
|
204
|
+
# post.comments.push(c2)
|
205
|
+
# post.comments.push(c3)
|
206
|
+
#
|
207
|
+
# [c1, c2] == post.comments.range(0, 1)
|
208
|
+
# # => true
|
209
|
+
def range(start, stop)
|
210
|
+
fetch(redis.call("LRANGE", key, start, stop))
|
211
|
+
end
|
212
|
+
|
181
213
|
# Checks if the model is part of this List.
|
182
214
|
#
|
183
215
|
# An important thing to note is that this method loads all of the
|
@@ -186,7 +218,7 @@ module Ohm
|
|
186
218
|
#
|
187
219
|
# You may want to avoid doing this if your list has say, 10K entries.
|
188
220
|
def include?(model)
|
189
|
-
ids.include?(model.id
|
221
|
+
ids.include?(model.id)
|
190
222
|
end
|
191
223
|
|
192
224
|
# Replace all the existing elements of a list with a different
|
@@ -206,13 +238,15 @@ module Ohm
|
|
206
238
|
# # => false
|
207
239
|
#
|
208
240
|
def replace(models)
|
209
|
-
ids = models.map
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
241
|
+
ids = models.map(&:id)
|
242
|
+
|
243
|
+
model.synchronize do
|
244
|
+
redis.queue("MULTI")
|
245
|
+
redis.queue("DEL", key)
|
246
|
+
ids.each { |id| redis.queue("RPUSH", key, id) }
|
247
|
+
redis.queue("EXEC")
|
248
|
+
redis.commit
|
249
|
+
end
|
216
250
|
end
|
217
251
|
|
218
252
|
# Pushes the model to the _end_ of the list using RPUSH.
|
@@ -236,7 +270,7 @@ module Ohm
|
|
236
270
|
# end
|
237
271
|
#
|
238
272
|
# class Post < Ohm::Model
|
239
|
-
# list :comments, Comment
|
273
|
+
# list :comments, :Comment
|
240
274
|
# end
|
241
275
|
#
|
242
276
|
# p = Post.create
|
@@ -256,11 +290,32 @@ module Ohm
|
|
256
290
|
redis.call("LREM", key, 0, model.id)
|
257
291
|
end
|
258
292
|
|
259
|
-
|
293
|
+
# Returns an array with all the ID's of the list.
|
294
|
+
#
|
295
|
+
# class Comment < Ohm::Model
|
296
|
+
# end
|
297
|
+
#
|
298
|
+
# class Post < Ohm::Model
|
299
|
+
# list :comments, :Comment
|
300
|
+
# end
|
301
|
+
#
|
302
|
+
# post = Post.create
|
303
|
+
# post.comments.push(Comment.create)
|
304
|
+
# post.comments.push(Comment.create)
|
305
|
+
# post.comments.push(Comment.create)
|
306
|
+
#
|
307
|
+
# post.comments.map(&:id)
|
308
|
+
# # => ["1", "2", "3"]
|
309
|
+
#
|
310
|
+
# post.comments.ids
|
311
|
+
# # => ["1", "2", "3"]
|
312
|
+
#
|
260
313
|
def ids
|
261
314
|
redis.call("LRANGE", key, 0, -1)
|
262
315
|
end
|
263
316
|
|
317
|
+
private
|
318
|
+
|
264
319
|
def redis
|
265
320
|
model.redis
|
266
321
|
end
|
@@ -270,9 +325,8 @@ module Ohm
|
|
270
325
|
class BasicSet
|
271
326
|
include Collection
|
272
327
|
|
273
|
-
# Allows you to sort by any
|
274
|
-
#
|
275
|
-
# Example:
|
328
|
+
# Allows you to sort by any attribute in the hash, this doesn't include
|
329
|
+
# the +id+. If you want to sort by ID, use #sort.
|
276
330
|
#
|
277
331
|
# class User < Ohm::Model
|
278
332
|
# attribute :name
|
@@ -365,7 +419,27 @@ module Ohm
|
|
365
419
|
end
|
366
420
|
end
|
367
421
|
|
368
|
-
#
|
422
|
+
# Returns an array with all the ID's of the set.
|
423
|
+
#
|
424
|
+
# class Post < Ohm::Model
|
425
|
+
# end
|
426
|
+
#
|
427
|
+
# class User < Ohm::Model
|
428
|
+
# attribute :name
|
429
|
+
# index :name
|
430
|
+
#
|
431
|
+
# set :posts, :Post
|
432
|
+
# end
|
433
|
+
#
|
434
|
+
# User.create(name: "John")
|
435
|
+
# User.create(name: "Jane")
|
436
|
+
#
|
437
|
+
# User.all.ids
|
438
|
+
# # => ["1", "2"]
|
439
|
+
#
|
440
|
+
# User.find(name: "John").union(name: "Jane").ids
|
441
|
+
# # => ["1", "2"]
|
442
|
+
#
|
369
443
|
def ids
|
370
444
|
execute { |key| redis.call("SMEMBERS", key) }
|
371
445
|
end
|
@@ -524,13 +598,15 @@ module Ohm
|
|
524
598
|
# # => false
|
525
599
|
#
|
526
600
|
def replace(models)
|
527
|
-
ids = models.map
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
601
|
+
ids = models.map(&:id)
|
602
|
+
|
603
|
+
model.synchronize do
|
604
|
+
redis.queue("MULTI")
|
605
|
+
redis.queue("DEL", key)
|
606
|
+
ids.each { |id| redis.queue("SADD", key, id) }
|
607
|
+
redis.queue("EXEC")
|
608
|
+
redis.commit
|
609
|
+
end
|
534
610
|
end
|
535
611
|
end
|
536
612
|
|
@@ -695,7 +771,15 @@ module Ohm
|
|
695
771
|
end
|
696
772
|
|
697
773
|
def self.redis
|
698
|
-
@redis
|
774
|
+
defined?(@redis) ? @redis : Ohm.redis
|
775
|
+
end
|
776
|
+
|
777
|
+
def self.mutex
|
778
|
+
@mutex ||= Mutex.new
|
779
|
+
end
|
780
|
+
|
781
|
+
def self.synchronize(&block)
|
782
|
+
mutex.synchronize(&block)
|
699
783
|
end
|
700
784
|
|
701
785
|
# Returns the namespace for all the keys generated using this model.
|
@@ -703,6 +787,7 @@ module Ohm
|
|
703
787
|
# Example:
|
704
788
|
#
|
705
789
|
# class User < Ohm::Model
|
790
|
+
# end
|
706
791
|
#
|
707
792
|
# User.key == "User"
|
708
793
|
# User.key.kind_of?(String)
|
data/lib/ohm/lua/save.lua
CHANGED
data/ohm.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "ohm"
|
3
|
-
s.version = "2.0.0.
|
3
|
+
s.version = "2.0.0.rc2"
|
4
4
|
s.summary = %{Object-hash mapping library for Redis.}
|
5
5
|
s.description = %Q{Ohm is a library that allows to store an object in Redis, a persistent key-value database. It has very good performance.}
|
6
6
|
s.authors = ["Michel Martens", "Damian Janowski", "Cyril David"]
|
data/test/association.rb
CHANGED
data/test/connection.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
|
1
|
+
require_relative 'helper'
|
2
2
|
|
3
|
-
|
3
|
+
test "model inherits Ohm.redis connection by default" do
|
4
|
+
class C < Ohm::Model
|
5
|
+
end
|
4
6
|
|
5
|
-
|
6
|
-
Redic::CannotConnectError = Errno::ECONNREFUSED
|
7
|
+
assert_equal C.redis.url, Ohm.redis.url
|
7
8
|
end
|
8
9
|
|
9
10
|
test "model can define its own connection" do
|
@@ -13,10 +14,3 @@ test "model can define its own connection" do
|
|
13
14
|
|
14
15
|
assert B.redis.url != Ohm.redis.url
|
15
16
|
end
|
16
|
-
|
17
|
-
test "model inherits Ohm.redis connection by default" do
|
18
|
-
class C < Ohm::Model
|
19
|
-
end
|
20
|
-
|
21
|
-
assert_equal C.redis.url, Ohm.redis.url
|
22
|
-
end
|
data/test/core.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require File.expand_path("./helper", File.dirname(__FILE__))
|
1
|
+
require_relative "helper"
|
4
2
|
|
5
3
|
class Event < Ohm::Model
|
6
4
|
attribute :name
|
@@ -8,19 +6,19 @@ class Event < Ohm::Model
|
|
8
6
|
end
|
9
7
|
|
10
8
|
test "assign attributes from the hash" do
|
11
|
-
event = Event.new(:
|
9
|
+
event = Event.new(name: "Ruby Tuesday")
|
12
10
|
assert_equal event.name, "Ruby Tuesday"
|
13
11
|
end
|
14
12
|
|
15
13
|
test "assign an ID and save the object" do
|
16
|
-
event1 = Event.create(:
|
17
|
-
event2 = Event.create(:
|
14
|
+
event1 = Event.create(name: "Ruby Tuesday")
|
15
|
+
event2 = Event.create(name: "Ruby Meetup")
|
18
16
|
|
19
|
-
assert_equal "1", event1.id
|
20
|
-
assert_equal "2", event2.id
|
17
|
+
assert_equal "1", event1.id
|
18
|
+
assert_equal "2", event2.id
|
21
19
|
end
|
22
20
|
|
23
21
|
test "save the attributes in UTF8" do
|
24
|
-
event = Event.create(:
|
25
|
-
|
22
|
+
event = Event.create(name: "32° Kisei-sen")
|
23
|
+
assert_equal "32° Kisei-sen", Event[event.id].name
|
26
24
|
end
|
data/test/counters.rb
CHANGED
data/test/enumerable.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative "helper"
|
2
2
|
|
3
3
|
scope do
|
4
4
|
class Contact < Ohm::Model
|
@@ -32,7 +32,7 @@ scope do
|
|
32
32
|
|
33
33
|
test "select" do |john, jane|
|
34
34
|
assert_equal 2, Contact.all.count
|
35
|
-
assert_equal [john], Contact.all.select { |c| c.id
|
35
|
+
assert_equal [john], Contact.all.select { |c| c.id == john.id }
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
data/test/filtering.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative "helper"
|
2
2
|
|
3
3
|
class User < Ohm::Model
|
4
4
|
attribute :fname
|
@@ -165,7 +165,7 @@ scope do
|
|
165
165
|
|
166
166
|
assert_equal 1, res.size
|
167
167
|
assert res.map(&:mood).include?("sad")
|
168
|
-
assert res.map(&:book_id).include?(book2.id
|
168
|
+
assert res.map(&:book_id).include?(book2.id)
|
169
169
|
end
|
170
170
|
|
171
171
|
test "@myobie usecase" do |book1, book2|
|
data/test/hash_key.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
|
4
|
-
|
5
1
|
begin
|
6
2
|
require "ruby-debug"
|
7
3
|
rescue LoadError
|
@@ -18,7 +14,7 @@ end unless defined?(silence_warnings)
|
|
18
14
|
|
19
15
|
$VERBOSE = true
|
20
16
|
|
21
|
-
|
17
|
+
require_relative "../lib/ohm"
|
22
18
|
|
23
19
|
Ohm.redis = Redic.new("redis://127.0.0.1:6379")
|
24
20
|
|
data/test/indices.rb
CHANGED
data/test/json.rb
CHANGED
data/test/list.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative "helper"
|
2
2
|
|
3
3
|
class Post < Ohm::Model
|
4
4
|
list :comments, :Comment
|
@@ -67,3 +67,17 @@ test "deleting main model cleans up the collection" do |p, _, _, _|
|
|
67
67
|
|
68
68
|
assert_equal 0, Ohm.redis.call("EXISTS", p.key[:comments])
|
69
69
|
end
|
70
|
+
|
71
|
+
test "#ids returns an array with the ids" do |post, *comments|
|
72
|
+
assert_equal comments.map(&:id), post.comments.ids
|
73
|
+
end
|
74
|
+
|
75
|
+
test "range" do |p, c1, c2, c3|
|
76
|
+
assert_equal 3, p.comments.range(0, 100).size
|
77
|
+
assert_equal [c1, c2, c3], p.comments.range(0, 2)
|
78
|
+
assert_equal [c1, c2], p.comments.range(0, 1)
|
79
|
+
assert_equal [c2, c3], p.comments.range(1, 2)
|
80
|
+
assert_equal [c1, c2, c3], p.comments.range(0, -1)
|
81
|
+
assert_equal [c1, c2], p.comments.range(0, -2)
|
82
|
+
assert_equal [c2, c3], p.comments.range(1, -1)
|
83
|
+
end
|
data/test/model.rb
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
-
|
1
|
+
require_relative "helper"
|
5
2
|
require "ostruct"
|
6
3
|
|
7
4
|
class Post < Ohm::Model
|
@@ -113,11 +110,11 @@ test "assign attributes from the hash" do
|
|
113
110
|
end
|
114
111
|
|
115
112
|
test "assign an ID and save the object" do
|
116
|
-
event1 = Event.create(:
|
117
|
-
event2 = Event.create(:
|
113
|
+
event1 = Event.create(name: "Ruby Tuesday")
|
114
|
+
event2 = Event.create(name: "Ruby Meetup")
|
118
115
|
|
119
|
-
|
120
|
-
|
116
|
+
assert_equal "1", event1.id
|
117
|
+
assert_equal "2", event2.id
|
121
118
|
end
|
122
119
|
|
123
120
|
test "updates attributes" do
|
@@ -138,14 +135,6 @@ test "delete the attribute if set to nil" do
|
|
138
135
|
assert_equal nil, Meetup[event.id].location
|
139
136
|
end
|
140
137
|
|
141
|
-
# FIXME: Failing test, as Meetup[event.id].location is returning "".
|
142
|
-
# test "delete the attribute if set to an empty string" do
|
143
|
-
# event = Meetup.create(:name => "Ruby Tuesday", :location => "Los Angeles")
|
144
|
-
# assert "Los Angeles" == Meetup[event.id].location
|
145
|
-
# assert event.update(:location => "")
|
146
|
-
# assert_equal nil, Meetup[event.id].location
|
147
|
-
# end
|
148
|
-
|
149
138
|
test "not raise if an attribute is redefined" do
|
150
139
|
class RedefinedModel < Ohm::Model
|
151
140
|
attribute :name
|
@@ -267,8 +256,8 @@ test "assign a new id to the event" do
|
|
267
256
|
assert !event1.new?
|
268
257
|
assert !event2.new?
|
269
258
|
|
270
|
-
|
271
|
-
|
259
|
+
assert_equal "1", event1.id
|
260
|
+
assert_equal "2", event2.id
|
272
261
|
end
|
273
262
|
|
274
263
|
# Saving a model
|
@@ -703,6 +692,8 @@ end
|
|
703
692
|
# Models connected to different databases
|
704
693
|
class ::Car < Ohm::Model
|
705
694
|
attribute :name
|
695
|
+
|
696
|
+
self.redis = Redic.new
|
706
697
|
end
|
707
698
|
|
708
699
|
class ::Make < Ohm::Model
|
@@ -711,7 +702,6 @@ end
|
|
711
702
|
|
712
703
|
setup do
|
713
704
|
Car.redis.call("SELECT", 15)
|
714
|
-
Car.redis.call("FLUSHDB")
|
715
705
|
end
|
716
706
|
|
717
707
|
test "save to the selected database" do
|
data/test/set.rb
CHANGED
@@ -4,6 +4,10 @@ class Post < Ohm::Model
|
|
4
4
|
end
|
5
5
|
|
6
6
|
class User < Ohm::Model
|
7
|
+
attribute :name
|
8
|
+
|
9
|
+
index :name
|
10
|
+
|
7
11
|
set :posts, :Post
|
8
12
|
end
|
9
13
|
|
@@ -18,3 +22,16 @@ test '#exists? returns true if the given id is included in the set' do
|
|
18
22
|
|
19
23
|
assert user.posts.exists?(post.id)
|
20
24
|
end
|
25
|
+
|
26
|
+
test "#ids returns an array with the ids" do
|
27
|
+
user_ids = [
|
28
|
+
User.create(name: "John").id,
|
29
|
+
User.create(name: "Jane").id
|
30
|
+
]
|
31
|
+
|
32
|
+
assert_equal user_ids, User.all.ids
|
33
|
+
|
34
|
+
result = User.find(name: "John").union(name: "Jane")
|
35
|
+
|
36
|
+
assert_equal user_ids, result.ids
|
37
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
class Post < Ohm::Model; end
|
4
|
+
class Role < Ohm::Model; end
|
5
|
+
|
6
|
+
class User < Ohm::Model
|
7
|
+
list :posts, :Post
|
8
|
+
set :roles, :Role
|
9
|
+
end
|
10
|
+
|
11
|
+
setup do
|
12
|
+
User.create
|
13
|
+
end
|
14
|
+
|
15
|
+
test "list#replace" do |user|
|
16
|
+
Post.mutex.lock
|
17
|
+
|
18
|
+
thread = Thread.new { user.posts.replace([Post.create]) }
|
19
|
+
|
20
|
+
sleep 0.1
|
21
|
+
|
22
|
+
assert_equal true, thread.alive?
|
23
|
+
|
24
|
+
Post.mutex.unlock
|
25
|
+
|
26
|
+
sleep 0.1
|
27
|
+
|
28
|
+
assert_equal false, thread.alive?
|
29
|
+
|
30
|
+
thread.join
|
31
|
+
end
|
32
|
+
|
33
|
+
test "set#replace" do |user|
|
34
|
+
Role.mutex.lock
|
35
|
+
|
36
|
+
thread = Thread.new { user.roles.replace([Role.create]) }
|
37
|
+
|
38
|
+
sleep 0.1
|
39
|
+
|
40
|
+
assert_equal true, thread.alive?
|
41
|
+
|
42
|
+
Role.mutex.unlock
|
43
|
+
|
44
|
+
sleep 0.1
|
45
|
+
|
46
|
+
assert_equal false, thread.alive?
|
47
|
+
|
48
|
+
thread.join
|
49
|
+
end
|
50
|
+
|
51
|
+
test "collection#fetch" do
|
52
|
+
User.mutex.lock
|
53
|
+
|
54
|
+
thread = Thread.new { User.all.to_a }
|
55
|
+
|
56
|
+
sleep 0.1
|
57
|
+
|
58
|
+
assert_equal true, thread.alive?
|
59
|
+
|
60
|
+
User.mutex.unlock
|
61
|
+
|
62
|
+
sleep 0.1
|
63
|
+
|
64
|
+
assert_equal false, thread.alive?
|
65
|
+
|
66
|
+
thread.join
|
67
|
+
end
|
data/test/uniques.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ohm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michel Martens
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2014-02-25 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: redic
|
@@ -80,7 +80,7 @@ extra_rdoc_files: []
|
|
80
80
|
files:
|
81
81
|
- .gems
|
82
82
|
- .gitignore
|
83
|
-
- CHANGELOG
|
83
|
+
- CHANGELOG.md
|
84
84
|
- LICENSE
|
85
85
|
- README.md
|
86
86
|
- Rakefile
|
@@ -113,12 +113,12 @@ files:
|
|
113
113
|
- test/hash_key.rb
|
114
114
|
- test/helper.rb
|
115
115
|
- test/indices.rb
|
116
|
-
- test/issue-52.rb
|
117
116
|
- test/json.rb
|
118
117
|
- test/list.rb
|
119
118
|
- test/model.rb
|
120
119
|
- test/set.rb
|
121
120
|
- test/test.conf
|
121
|
+
- test/thread_safety.rb
|
122
122
|
- test/to_hash.rb
|
123
123
|
- test/uniques.rb
|
124
124
|
homepage: http://soveran.github.io/ohm/
|
data/CHANGELOG
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
(unreleased)
|
2
|
-
|
3
|
-
- Include Ohm::BasicSet#exists? in the public API. This makes possible
|
4
|
-
to check if an id is included in a set. Check Ohm::BasicSet#exists?
|
5
|
-
documentation for more details.
|
6
|
-
|
7
|
-
- Change Ohm::MultiSet#except to union keys instead of intersect them
|
8
|
-
when passing an array.
|
9
|
-
|
10
|
-
class User < Ohm::Model
|
11
|
-
attribute :name
|
12
|
-
end
|
13
|
-
|
14
|
-
john = User.create(:name => "John")
|
15
|
-
jane = User.create(:name => "Jane")
|
16
|
-
|
17
|
-
res = User.all.except(:name => [john.name, jane.name])
|
18
|
-
|
19
|
-
# before
|
20
|
-
res.size # => 2
|
21
|
-
|
22
|
-
# now
|
23
|
-
res.size # => 0
|
24
|
-
|
25
|
-
- Move ID generation to Lua. With this change, it's no longer possible
|
26
|
-
to generate custom ids. All ids are autoincremented.
|
27
|
-
|
28
|
-
- Ohm::Model#reference accepts strings as model references. For example:
|
29
|
-
|
30
|
-
class Bar < Ohm::Model
|
31
|
-
reference :foo, "SomeNamespace::Foo"
|
32
|
-
end
|
33
|
-
|
34
|
-
- Nest dependency has been removed. Now, Ohm uses Nido
|
35
|
-
(https://github.com/soveran/nido) to generate the keys that hold
|
36
|
-
the data.
|
37
|
-
|
38
|
-
- Scrivener dependency has been removed.
|
39
|
-
|
40
|
-
- Ohm no longer supports model validations and favors filter validation
|
41
|
-
on the boundary layer. Check Scrivener project
|
42
|
-
(https://github.com/soveran/scrivener) for more information.
|
43
|
-
|
44
|
-
- Redis dependency has been removed. Now, Ohm uses Redic
|
45
|
-
(https://github.com/amakawa/redic), a lightweight Redis client.
|
46
|
-
Redic uses the hiredis gem for the connection and for parsing
|
47
|
-
the replies. Check Redic's README for more details.
|
48
|
-
|
49
|
-
- Ohm::Model#transaction has been removed.
|
50
|
-
|
51
|
-
- Ohm::Transaction has been removed.
|
52
|
-
|
53
|
-
1.3.2
|
54
|
-
|
55
|
-
- Fetching a batch of objects is now done in batches of 1000 objects at
|
56
|
-
a time. If you are iterating over large collections, this change should
|
57
|
-
provide a significant performance boost both in used memory and total
|
58
|
-
execution time.
|
59
|
-
- MutableSet#<< is now an alias for #add.
|
60
|
-
|
61
|
-
1.3.1
|
62
|
-
|
63
|
-
- Improve memory consumption when indexing persisted attributes.
|
64
|
-
|
65
|
-
No migration is needed and old indices will be cleaned up as you save
|
66
|
-
instances.
|
67
|
-
|
68
|
-
1.3.0
|
69
|
-
|
70
|
-
- Add Model.attributes.
|
71
|
-
|
72
|
-
1.2.0
|
73
|
-
|
74
|
-
- Enumerable fix.
|
75
|
-
- Merge Ohm::PipelinedFetch into Ohm::Collection.
|
76
|
-
- Fix Set, MultiSet, and List enumerable behavior.
|
77
|
-
- Change dependencies to use latest cutest.
|
78
|
-
|
79
|
-
1.1.0
|
80
|
-
|
81
|
-
- Compatible with redis-rb 3.
|
82
|
-
|
83
|
-
1.0.0
|
84
|
-
|
85
|
-
- Fetching a batch of objects is now done through one pipeline, effectively
|
86
|
-
reducing the IO to just 2 operations (one for SMEMBERS / LRANGE, one for
|
87
|
-
the actual HGET of all the individual HASHes.)
|
88
|
-
- write_remote / read_remote have been replaced with set / get respectively.
|
89
|
-
- Ohm::Model.unique has been added.
|
90
|
-
- Ohm::Model::Set has been renamed to Ohm::Set
|
91
|
-
- Ohm::Model::List has been renamed to Ohm::List
|
92
|
-
- Ohm::Model::Collection is gone.
|
93
|
-
- Ohm::Validations is gone. Ohm now uses Scrivener::Validations.
|
94
|
-
- Ohm::Key is gone. Ohm now uses Nest directly.
|
95
|
-
- No more concept of volatile keys.
|
96
|
-
- Ohm::Model::Wrapper is gone.
|
97
|
-
- Use Symbols for constants instead of relying on Ohm::Model.const_missing.
|
98
|
-
- #sort / #sort_by now uses `limit` as it's used in redis-rb, e.g. you
|
99
|
-
have to pass in an array like so: sort(limit: [0, 1]).
|
100
|
-
- Set / List have been trimmed to contain only the minimum number
|
101
|
-
of necessary methods.
|
102
|
-
- You can no longer mutate a collection / set as before, e.g. doing
|
103
|
-
User.find(...).add(User[1]) will throw an error.
|
104
|
-
- The #union operation has been added. You can now chain it with your filters.
|
105
|
-
- Temporary keys when doing finds are now automatically cleaned up.
|
106
|
-
- Counters are now stored in their own key instead, i.e. in
|
107
|
-
User:<id>:counters.
|
108
|
-
- JSON support has to be explicitly required by doing `require
|
109
|
-
"ohm/json"`.
|
110
|
-
- All save / delete / update operations are now done using
|
111
|
-
transactions (see http://redis.io/topics/transactions).
|
112
|
-
- All indices are now stored without converting the values to base64.
|
data/test/issue-52.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
require_relative "helper"
|
2
|
-
|
3
|
-
class Model < Ohm::Model
|
4
|
-
attribute :hash
|
5
|
-
index :hash
|
6
|
-
|
7
|
-
attribute :data
|
8
|
-
end
|
9
|
-
|
10
|
-
test do
|
11
|
-
50.times do |i|
|
12
|
-
Ohm.flush
|
13
|
-
|
14
|
-
Model.create(:hash => "123")
|
15
|
-
|
16
|
-
assert_equal 1, Ohm.redis.call("SCARD", "Model:all")
|
17
|
-
|
18
|
-
Thread.new do
|
19
|
-
a = Model.find(:hash => "123").first
|
20
|
-
a.update(:data => "2")
|
21
|
-
end
|
22
|
-
|
23
|
-
sleep 0.01
|
24
|
-
|
25
|
-
b = Model.find(:hash => "123").first
|
26
|
-
|
27
|
-
if Ohm.redis.call("SCARD", "Model:indices:hash:123") != 1
|
28
|
-
flunk("Failed at iteration %d" % i)
|
29
|
-
end
|
30
|
-
|
31
|
-
assert ! b.nil?
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|