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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60d1fadf47380356ffbc44627e28f9b15ff8528a
4
- data.tar.gz: f911d9c462235f7c56f5216b10f1b2d48f3ab287
3
+ metadata.gz: 44f992bf97d394e618f9e3608a13999e6a37ffbf
4
+ data.tar.gz: 9e97ba2177d8067c64ab4e2b0b7a0a710703bb18
5
5
  SHA512:
6
- metadata.gz: 67eea41a25fd17691a9cc79700abf248438a7bccefc7624053212d6439d6252bfc2850e0a7905fe8a2ad46eadac6d9d11d150978cec4f937a2bbba89ea05e90b
7
- data.tar.gz: 1e17aace64652f6c96cd79fa6ff071a67fbed614951af15e8487d8fee78b21ec69f10313b7e8b1004292d1f97a22c3d8be74d5f892172742fe634fea84989ef2
6
+ metadata.gz: a0d5bc81d2fa070ee3b9306844bc61a1d089cf67e464fd8c3939274db918d986f3e6d97c8166ae3f1caf2c0d679c7c1802c55499d65dc0ca35a619ee9446b342
7
+ data.tar.gz: 50008d8d644b1825507db45e921e78aaa0cd19b48fc587eca43605495155d91e816e49abc75a02f6bc4aef1e5351c81940384da4eb97c8e3e8eb6934ba75ce65
data/.gems CHANGED
@@ -1,4 +1,4 @@
1
- nido -v 0.0.1
2
1
  cutest -v 1.2.0
3
- msgpack -v 0.5.4
4
- redic -v 0.0.5
2
+ msgpack -v 0.5.8
3
+ nido -v 0.0.1
4
+ redic -v 1.0.1
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
@@ -48,7 +48,7 @@ with the sources if you want to change some settings.
48
48
 
49
49
  If you don't have Ohm, try this:
50
50
 
51
- $ [sudo] gem install ohm
51
+ $ [sudo] gem install ohm -v 2.0.0.rc1
52
52
 
53
53
  Or you can grab the code from [http://github.com/soveran/ohm][ohm].
54
54
 
data/benchmarks/common.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "bench"
2
2
  require_relative "../lib/ohm"
3
3
 
4
- Ohm.connect(:port => 6379, :db => 15)
4
+ Ohm.redis = Redic.new("redis://127.0.0.1:6379/15")
5
5
  Ohm.flush
6
6
 
7
7
  class Event < Ohm::Model
@@ -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
- # post "/comments.json" do
9
- # comment = Comment.create(params[:comment])
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`. In ruby 1.9, `json` is
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 verify our code. We
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(:title => "my post")
33
+ post = Post.create(title: "my post")
44
34
 
45
- assert({ :id => "1" } == post.to_hash)
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(:title => "my post")
52
-
53
- assert("{\"id\":\"1\"}" == post.to_json)
54
- end
41
+ post = Post.create(title: "my post")
55
42
 
56
- # Let's try and do the opposite now -- that is, purposely try and create
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 in other frameworks which dumps out all attributes by default,
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` and `:errors` will be available, depending if
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(:title => title)
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(:title => "Override FTW?")
92
- assert({ :id => "1", :title => "Override FTW?" } == post.to_hash)
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
- require "ohm/command"
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
- ids.each do |id|
138
- redis.queue("HGETALL", namespace[id])
139
- end
137
+ data = nil
138
+
139
+ model.synchronize do
140
+ ids.each do |id|
141
+ redis.queue("HGETALL", namespace[id])
142
+ end
140
143
 
141
- data = redis.commit
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.to_s)
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 { |model| model.id }
210
-
211
- redis.queue("MULTI")
212
- redis.queue("DEL", key)
213
- ids.each { |id| redis.queue("RPUSH", key, id) }
214
- redis.queue("EXEC")
215
- redis.commit
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
- private
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 field in your model.
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
- # Grab all the elements of this set using SMEMBERS.
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 { |model| model.id }
528
-
529
- redis.queue("MULTI")
530
- redis.queue("DEL", key)
531
- ids.each { |id| redis.queue("SADD", key, id) }
532
- redis.queue("EXEC")
533
- redis.commit
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 ||= Redic.new(Ohm.redis.url)
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
@@ -122,4 +122,4 @@ index(model, indices)
122
122
  remove_uniques(model, uniques)
123
123
  unique(model, uniques)
124
124
 
125
- return model.id
125
+ return tostring(model.id)
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.rc1"
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
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
2
2
 
3
3
  class User < Ohm::Model
4
4
  collection :posts, :Post
data/test/connection.rb CHANGED
@@ -1,9 +1,10 @@
1
- # encoding: UTF-8
1
+ require_relative 'helper'
2
2
 
3
- require File.expand_path("./helper", File.dirname(__FILE__))
3
+ test "model inherits Ohm.redis connection by default" do
4
+ class C < Ohm::Model
5
+ end
4
6
 
5
- unless defined?(Redic::CannotConnectError)
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
- # encoding: UTF-8
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(:name => "Ruby Tuesday")
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(:name => "Ruby Tuesday")
17
- event2 = Event.create(:name => "Ruby Meetup")
14
+ event1 = Event.create(name: "Ruby Tuesday")
15
+ event2 = Event.create(name: "Ruby Meetup")
18
16
 
19
- assert_equal "1", event1.id.to_s
20
- assert_equal "2", event2.id.to_s
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(:name => "32° Kisei-sen")
25
- assert "32° Kisei-sen" == Event[event.id].name
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
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
2
2
 
3
3
  $VERBOSE = false
4
4
 
data/test/enumerable.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
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.to_s == john.id.to_s }
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
- require File.expand_path("./helper", File.dirname(__FILE__))
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.to_s)
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
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class Tag < Ohm::Model
6
4
  attribute :name
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
- require "ohm"
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
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class User < Ohm::Model
6
4
  attribute :email
data/test/json.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require_relative 'helper'
2
-
3
- require "ohm/json"
2
+ require_relative "../lib/ohm/json"
4
3
 
5
4
  class Venue < Ohm::Model
6
5
  attribute :name
data/test/list.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
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
- # encoding: UTF-8
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(:name => "Ruby Tuesday")
117
- event2 = Event.create(:name => "Ruby Meetup")
113
+ event1 = Event.create(name: "Ruby Tuesday")
114
+ event2 = Event.create(name: "Ruby Meetup")
118
115
 
119
- assert 1 == event1.id
120
- assert 2 == event2.id
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
- assert 1 == event1.id
271
- assert 2 == event2.id
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
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class User < Ohm::Model
6
4
  attribute :email
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.rc1
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: 2013-12-18 00:00:00.000000000 Z
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
-