ohm 2.0.0.rc1 → 2.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.
- 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
|
-
|