redis_orm 0.5 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/Manifest +1 -0
- data/README.md +71 -20
- data/Rakefile +2 -2
- data/lib/redis_orm.rb +1 -0
- data/lib/redis_orm/redis_orm.rb +22 -7
- data/redis_orm.gemspec +12 -9
- data/test/atomicity_test.rb +39 -0
- data/test/uuid_as_id_test.rb +210 -0
- metadata +26 -11
data/CHANGELOG
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
v0.5.1 [27-07-2011]
|
2
|
+
* added support of uuid as an id/primary key
|
3
|
+
* added documentation on uuid support and connection to the redis server
|
4
|
+
|
1
5
|
v0.5 [02-07-2011]
|
2
6
|
* added support of *:conditions* hash in *:options* hash for has_many association in #find/#all methods
|
3
7
|
* made keys order-independent in *:conditions* hash
|
data/Manifest
CHANGED
data/README.md
CHANGED
@@ -27,6 +27,15 @@ class User < RedisOrm::Base
|
|
27
27
|
end
|
28
28
|
```
|
29
29
|
|
30
|
+
## Setting up a connection to the redis server
|
31
|
+
|
32
|
+
If you are using Rails you should initialize redis and set up global $redis variable in *config/initializers/redis.rb* file:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
require 'redis'
|
36
|
+
$redis = Redis.new(:host => 'localhost', :port => 6379)
|
37
|
+
```
|
38
|
+
|
30
39
|
## Defining a model and specifing properties
|
31
40
|
|
32
41
|
To specify properties for your model you should use the following syntax:
|
@@ -61,7 +70,7 @@ Following options are available in property declaration:
|
|
61
70
|
|
62
71
|
## Searching records by the value
|
63
72
|
|
64
|
-
Usually it's done via declaring an index and using dynamic finders
|
73
|
+
Usually it's done via declaring an index and using *:conditions* hash or dynamic finders. For example:
|
65
74
|
|
66
75
|
```ruby
|
67
76
|
class User < RedisOrm::Base
|
@@ -71,15 +80,21 @@ class User < RedisOrm::Base
|
|
71
80
|
end
|
72
81
|
|
73
82
|
User.create :name => "germaninthetown"
|
83
|
+
|
84
|
+
# via dynamic finders:
|
74
85
|
User.find_by_name "germaninthetown" # => found 1 record
|
75
86
|
User.find_all_by_name "germaninthetown" # => array with 1 record
|
87
|
+
|
88
|
+
# via *:conditions* hash:
|
89
|
+
User.find(:all, :conditions => {:name => "germaninthetown"}) # => array with 1 record
|
90
|
+
User.all(:conditions => {:name => "germaninthetown"}) # => array with 1 record
|
76
91
|
```
|
77
92
|
|
78
|
-
Dynamic finders work mostly the way they
|
93
|
+
Dynamic finders work mostly the way they work in ActiveRecord. The only difference is if you didn't specified index or compound index on the attributes you are searching on the exception will be raised. So you should make an initial analysis of model and determine properties that should be searchable.
|
79
94
|
|
80
95
|
## Options for #find/#all
|
81
96
|
|
82
|
-
To extract all or part of the associated records you could use 4 options
|
97
|
+
To extract all or part of the associated records you could use 4 options:
|
83
98
|
|
84
99
|
* :limit
|
85
100
|
|
@@ -87,20 +102,20 @@ To extract all or part of the associated records you could use 4 options for now
|
|
87
102
|
|
88
103
|
* :order
|
89
104
|
|
90
|
-
Either :desc or :asc (default), since records are stored with Time.now.to_f scores, by default they could be fetched only in that (or reversed) order. To store them in different order you should *zadd* record's id to some other sorted list manually.
|
105
|
+
Either :desc or :asc (default), since records are stored with *Time.now.to_f* scores, by default they could be fetched only in that (or reversed) order. To store them in different order you should *zadd* record's id to some other sorted list manually.
|
91
106
|
|
92
107
|
* :conditions
|
93
108
|
|
94
|
-
Hash where keys must be equal to
|
109
|
+
Hash where keys must be equal to the existing property name (there must be index for this property too).
|
95
110
|
|
96
111
|
```ruby
|
97
112
|
# for example we associate 2 photos with the album
|
98
|
-
@album.photos <<
|
99
|
-
@album.photos <<
|
113
|
+
@album.photos << Photo.create(:image_type => "image/png", :image => "boobs.png")
|
114
|
+
@album.photos << Photo.create(:image_type => "image/jpeg", :image => "facepalm.jpg")
|
100
115
|
|
101
116
|
@album.photos.all(:limit => 0, :offset => 0) # => []
|
102
117
|
@album.photos.all(:limit => 1, :offset => 0).size # => 1
|
103
|
-
@album.photos.all(:limit => 2, :offset => 0)
|
118
|
+
@album.photos.all(:limit => 2, :offset => 0) # [...]
|
104
119
|
@album.photos.all(:limit => 1, :offset => 1, :conditions => {:image_type => "image/png"})
|
105
120
|
@album.photos.find(:all, :order => "asc")
|
106
121
|
|
@@ -110,14 +125,50 @@ Photo.all(:order => "desc", :limit => 10, :offset => 50)
|
|
110
125
|
Photo.all(:order => "desc", :offset => 10, :conditions => {:image_type => "image/jpeg"})
|
111
126
|
|
112
127
|
Photo.find(:all, :conditions => {:image => "facepalm.jpg"}) # => [...]
|
113
|
-
Photo.find(:first, :conditions => {:image => "boobs.png"}) # =>
|
128
|
+
Photo.find(:first, :conditions => {:image => "boobs.png"}) # => [...]
|
129
|
+
```
|
130
|
+
|
131
|
+
## Using UUID instead of numeric id
|
132
|
+
|
133
|
+
You could use universally unique identifiers (UUIDs) instead of a monotone increasing sequence of numbers as id/primary key for your models.
|
134
|
+
|
135
|
+
Example of UUID: b57525b09a69012e8fbe001d61192f09.
|
136
|
+
|
137
|
+
To enable UUIDs you should invoke *use_uuid_as_id* class method:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
class User < RedisOrm::Base
|
141
|
+
use_uuid_as_id
|
142
|
+
|
143
|
+
property :name, String
|
144
|
+
|
145
|
+
property :created_at, Time
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
[UUID](https://rubygems.org/gems/uuid) gem is installed as a dependency.
|
150
|
+
|
151
|
+
An excerpt from https://github.com/assaf/uuid :
|
152
|
+
|
153
|
+
UUID (universally unique identifier) are guaranteed to be unique across time and space.
|
154
|
+
|
155
|
+
A UUID is 128 bit long, and consists of a 60-bit time value, a 16-bit sequence number and a 48-bit node identifier.
|
156
|
+
|
157
|
+
Note: when using a forking server (Unicorn, Resque, Pipemaster, etc) you don’t want your forked processes using the same sequence number. Make sure to increment the sequence number each time a worker forks.
|
158
|
+
|
159
|
+
For example, in config/unicorn.rb:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
after_fork do |server, worker|
|
163
|
+
UUID.generator.next_sequence
|
164
|
+
end
|
114
165
|
```
|
115
166
|
|
116
167
|
## Indices
|
117
168
|
|
118
|
-
Indices are used in a different way then they are used in relational databases.
|
169
|
+
Indices are used in a different way then they are used in relational databases. In redis_orm they are used to find record by they value rather then to quick access them.
|
119
170
|
|
120
|
-
You could add index to any attribute of the model (
|
171
|
+
You could add index to any attribute of the model (index also could be compound):
|
121
172
|
|
122
173
|
```ruby
|
123
174
|
class User < RedisOrm::Base
|
@@ -129,13 +180,13 @@ class User < RedisOrm::Base
|
|
129
180
|
end
|
130
181
|
```
|
131
182
|
|
132
|
-
With index defined for the property (or properties) the id of the saved object is stored in the
|
183
|
+
With index defined for the property (or properties) the id of the saved object is stored in the sorted set with special name, so it could be found later by the value. For example with defined User model from the above code:
|
133
184
|
|
134
185
|
```ruby
|
135
186
|
user = User.new :first_name => "Robert", :last_name => "Pirsig"
|
136
187
|
user.save
|
137
188
|
|
138
|
-
# 2 redis keys are created "user:first_name:Robert" and "user:first_name:Robert:last_name:Pirsig" so we could search
|
189
|
+
# 2 redis keys are created "user:first_name:Robert" and "user:first_name:Robert:last_name:Pirsig" so we could search records like this:
|
139
190
|
|
140
191
|
User.find_by_first_name("Robert") # => user
|
141
192
|
User.find_all_by_first_name("Robert") # => [user]
|
@@ -164,7 +215,7 @@ comment2 = Comment.create :body => "test #2", :moderated => true
|
|
164
215
|
|
165
216
|
article.comments << [comment1, comment2]
|
166
217
|
|
167
|
-
# here besides usual indices for each comment, 2 association indices are created so #find with *:conditions* on comments
|
218
|
+
# here besides usual indices for each comment, 2 association indices are created so #find with *:conditions* on comments should work
|
168
219
|
|
169
220
|
article.comments.find(:all, :conditions => {:moderated => true})
|
170
221
|
article.comments.find(:all, :conditions => {:moderated => false})
|
@@ -174,11 +225,11 @@ Index definition supports following options:
|
|
174
225
|
|
175
226
|
* **:unique** Boolean default: false
|
176
227
|
|
177
|
-
If true is specified then value is stored in ordinary key-value structure with index as the key, otherwise the values are added to sorted set with index as the key.
|
228
|
+
If true is specified then value is stored in ordinary key-value structure with index as the key, otherwise the values are added to sorted set with index as the key and *Time.now.to_f* as a score.
|
178
229
|
|
179
230
|
* **:case_insensitive** Boolean default: false
|
180
231
|
|
181
|
-
If true is specified then property values are saved downcased (and then are transformed to downcase form when searching
|
232
|
+
If true is specified then property values are saved downcased (and then are transformed to downcase form when searching). Works for compound indices too.
|
182
233
|
|
183
234
|
## Associations
|
184
235
|
|
@@ -372,7 +423,7 @@ For more examples please check test/associations_test.rb and test/polymorphic_te
|
|
372
423
|
|
373
424
|
## Validation
|
374
425
|
|
375
|
-
RedisOrm includes ActiveModel::Validations. So all well-known
|
426
|
+
RedisOrm includes ActiveModel::Validations. So all well-known validation callbacks are already in. An excerpt from test/validations_test.rb:
|
376
427
|
|
377
428
|
```ruby
|
378
429
|
class Photo < RedisOrm::Base
|
@@ -417,7 +468,7 @@ end
|
|
417
468
|
|
418
469
|
When saving object standard ActiveModel's #valid? method is invoked at first. Then appropriate callbacks are run. Then new Hash in Redis is created with keys/values equal to the properties/values of the saving object.
|
419
470
|
|
420
|
-
The object's id is stored in "model_name:ids" sorted set with Time.now.to_f as a score. So records are ordered by created_at time by default.
|
471
|
+
The object's id is stored in "model_name:ids" sorted set with Time.now.to_f as a score. So records are ordered by created_at time by default. Then record's indices are created/updated.
|
421
472
|
|
422
473
|
## Dirty
|
423
474
|
|
@@ -425,11 +476,11 @@ Redis_orm also provides dirty methods to check whether the property has changed
|
|
425
476
|
|
426
477
|
## File attachment management with paperclip and redis
|
427
478
|
|
428
|
-
|
479
|
+
[3 simple steps](http://def-end.com/post/6669884103/file-attachment-management-with-paperclip-and-redis) you should follow to manage your file attachments with redis and paperclip.
|
429
480
|
|
430
481
|
## Tests
|
431
482
|
|
432
|
-
Though I'm a big fan of the Test::Unit all tests are based on RSpec. And the only reason I
|
483
|
+
Though I'm a big fan of the Test::Unit all tests are based on RSpec. And the only reason I use RSpec is possibility to define *before(:all)* and *after(:all)* hooks. So I could spawn/kill redis-server's process (from test_helper.rb):
|
433
484
|
|
434
485
|
```ruby
|
435
486
|
RSpec.configure do |config|
|
data/Rakefile
CHANGED
@@ -4,12 +4,12 @@ require 'rake'
|
|
4
4
|
#=begin
|
5
5
|
require 'echoe'
|
6
6
|
|
7
|
-
Echoe.new('redis_orm', '0.5') do |p|
|
7
|
+
Echoe.new('redis_orm', '0.5.1') do |p|
|
8
8
|
p.description = "ORM for Redis (advanced key-value storage) with ActiveRecord API"
|
9
9
|
p.url = "https://github.com/german/redis_orm"
|
10
10
|
p.author = "Dmitrii Samoilov"
|
11
11
|
p.email = "germaninthetown@gmail.com"
|
12
|
-
p.dependencies = ["activesupport >=3.0.0", "activemodel >=3.0.0", "redis >=2.2.0"]
|
12
|
+
p.dependencies = ["activesupport >=3.0.0", "activemodel >=3.0.0", "redis >=2.2.0", "uuid >=2.3.2"]
|
13
13
|
p.development_dependencies = ["rspec >=2.5.0"]
|
14
14
|
end
|
15
15
|
#=end
|
data/lib/redis_orm.rb
CHANGED
data/lib/redis_orm/redis_orm.rb
CHANGED
@@ -41,8 +41,9 @@ module RedisOrm
|
|
41
41
|
@@properties = Hash.new{|h,k| h[k] = []}
|
42
42
|
@@indices = Hash.new{|h,k| h[k] = []} # compound indices are available too
|
43
43
|
@@associations = Hash.new{|h,k| h[k] = []}
|
44
|
-
@@callbacks = Hash.new{|h,k| h[k] = {}}
|
45
|
-
|
44
|
+
@@callbacks = Hash.new{|h,k| h[k] = {}}
|
45
|
+
@@use_uuid_as_id = {}
|
46
|
+
|
46
47
|
class << self
|
47
48
|
|
48
49
|
def inherited(from)
|
@@ -116,6 +117,11 @@ module RedisOrm
|
|
116
117
|
end
|
117
118
|
end
|
118
119
|
|
120
|
+
def use_uuid_as_id
|
121
|
+
@@use_uuid_as_id[model_name] = true
|
122
|
+
@@uuid = UUID.new
|
123
|
+
end
|
124
|
+
|
119
125
|
def count
|
120
126
|
$redis.zcard("#{model_name}:ids").to_i
|
121
127
|
end
|
@@ -321,8 +327,10 @@ module RedisOrm
|
|
321
327
|
|
322
328
|
def initialize(attributes = {}, id = nil, persisted = false)
|
323
329
|
@persisted = persisted
|
324
|
-
|
325
|
-
|
330
|
+
|
331
|
+
id = @@use_uuid_as_id[model_name] ? id : id.to_i
|
332
|
+
|
333
|
+
instance_variable_set(:"@id", id) if id
|
326
334
|
|
327
335
|
# when object is created with empty attribute set @#{prop[:name]}_changes array properly
|
328
336
|
@@properties[model_name].each do |prop|
|
@@ -349,6 +357,14 @@ module RedisOrm
|
|
349
357
|
@persisted
|
350
358
|
end
|
351
359
|
|
360
|
+
def get_next_id
|
361
|
+
if @@use_uuid_as_id[model_name]
|
362
|
+
@@uuid.generate(:compact)
|
363
|
+
else
|
364
|
+
$redis.incr("#{model_name}:id")
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
352
368
|
def save
|
353
369
|
return false if !valid?
|
354
370
|
|
@@ -428,10 +444,9 @@ module RedisOrm
|
|
428
444
|
self.send(callback)
|
429
445
|
end
|
430
446
|
|
431
|
-
@id =
|
447
|
+
@id = get_next_id
|
432
448
|
$redis.zadd "#{model_name}:ids", Time.now.to_f, @id
|
433
449
|
@persisted = true
|
434
|
-
|
435
450
|
self.created_at = Time.now if respond_to? :created_at
|
436
451
|
end
|
437
452
|
|
@@ -463,7 +478,7 @@ module RedisOrm
|
|
463
478
|
end
|
464
479
|
|
465
480
|
# save new indices in order to sort by finders
|
466
|
-
# city:name
|
481
|
+
# city:name:Chicago => 1
|
467
482
|
@@indices[model_name].each do |index|
|
468
483
|
prepared_index = construct_prepared_index(index) # instance method not class one!
|
469
484
|
|
data/redis_orm.gemspec
CHANGED
@@ -2,22 +2,22 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{redis_orm}
|
5
|
-
s.version = "0.5"
|
5
|
+
s.version = "0.5.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
-
s.authors = [
|
9
|
-
s.date = %q{2011-07-
|
8
|
+
s.authors = ["Dmitrii Samoilov"]
|
9
|
+
s.date = %q{2011-07-27}
|
10
10
|
s.description = %q{ORM for Redis (advanced key-value storage) with ActiveRecord API}
|
11
11
|
s.email = %q{germaninthetown@gmail.com}
|
12
|
-
s.extra_rdoc_files = [
|
13
|
-
s.files = [
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md", "lib/redis_orm.rb", "lib/redis_orm/active_model_behavior.rb", "lib/redis_orm/associations/belongs_to.rb", "lib/redis_orm/associations/has_many.rb", "lib/redis_orm/associations/has_many_helper.rb", "lib/redis_orm/associations/has_many_proxy.rb", "lib/redis_orm/associations/has_one.rb", "lib/redis_orm/redis_orm.rb"]
|
13
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.md", "Rakefile", "lib/redis_orm.rb", "lib/redis_orm/active_model_behavior.rb", "lib/redis_orm/associations/belongs_to.rb", "lib/redis_orm/associations/has_many.rb", "lib/redis_orm/associations/has_many_helper.rb", "lib/redis_orm/associations/has_many_proxy.rb", "lib/redis_orm/associations/has_one.rb", "lib/redis_orm/redis_orm.rb", "redis_orm.gemspec", "test/association_indices_test.rb", "test/associations_test.rb", "test/atomicity_test.rb", "test/basic_functionality_test.rb", "test/callbacks_test.rb", "test/changes_array_test.rb", "test/dynamic_finders_test.rb", "test/exceptions_test.rb", "test/has_one_has_many_test.rb", "test/indices_test.rb", "test/options_test.rb", "test/polymorphic_test.rb", "test/redis.conf", "test/test_helper.rb", "test/uuid_as_id_test.rb", "test/validations_test.rb"]
|
14
14
|
s.homepage = %q{https://github.com/german/redis_orm}
|
15
|
-
s.rdoc_options = [
|
16
|
-
s.require_paths = [
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Redis_orm", "--main", "README.md"]
|
16
|
+
s.require_paths = ["lib"]
|
17
17
|
s.rubyforge_project = %q{redis_orm}
|
18
|
-
s.rubygems_version = %q{1.
|
18
|
+
s.rubygems_version = %q{1.6.2}
|
19
19
|
s.summary = %q{ORM for Redis (advanced key-value storage) with ActiveRecord API}
|
20
|
-
s.test_files = [
|
20
|
+
s.test_files = ["test/options_test.rb", "test/dynamic_finders_test.rb", "test/associations_test.rb", "test/validations_test.rb", "test/test_helper.rb", "test/polymorphic_test.rb", "test/uuid_as_id_test.rb", "test/atomicity_test.rb", "test/exceptions_test.rb", "test/association_indices_test.rb", "test/has_one_has_many_test.rb", "test/indices_test.rb", "test/changes_array_test.rb", "test/callbacks_test.rb", "test/basic_functionality_test.rb"]
|
21
21
|
|
22
22
|
if s.respond_to? :specification_version then
|
23
23
|
s.specification_version = 3
|
@@ -26,17 +26,20 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0"])
|
27
27
|
s.add_runtime_dependency(%q<activemodel>, [">= 3.0.0"])
|
28
28
|
s.add_runtime_dependency(%q<redis>, [">= 2.2.0"])
|
29
|
+
s.add_runtime_dependency(%q<uuid>, [">= 2.3.2"])
|
29
30
|
s.add_development_dependency(%q<rspec>, [">= 2.5.0"])
|
30
31
|
else
|
31
32
|
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
32
33
|
s.add_dependency(%q<activemodel>, [">= 3.0.0"])
|
33
34
|
s.add_dependency(%q<redis>, [">= 2.2.0"])
|
35
|
+
s.add_dependency(%q<uuid>, [">= 2.3.2"])
|
34
36
|
s.add_dependency(%q<rspec>, [">= 2.5.0"])
|
35
37
|
end
|
36
38
|
else
|
37
39
|
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
38
40
|
s.add_dependency(%q<activemodel>, [">= 3.0.0"])
|
39
41
|
s.add_dependency(%q<redis>, [">= 2.2.0"])
|
42
|
+
s.add_dependency(%q<uuid>, [">= 2.3.2"])
|
40
43
|
s.add_dependency(%q<rspec>, [">= 2.5.0"])
|
41
44
|
end
|
42
45
|
end
|
data/test/atomicity_test.rb
CHANGED
@@ -6,6 +6,7 @@ class Article < RedisOrm::Base
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe "check atomicity" do
|
9
|
+
=begin
|
9
10
|
it "should properly increment property's value" do
|
10
11
|
@article = Article.new :title => "Simple test atomicity with multiple threads", :karma => 1
|
11
12
|
@article.save
|
@@ -14,6 +15,7 @@ describe "check atomicity" do
|
|
14
15
|
|
15
16
|
50.times do |i|
|
16
17
|
@threads << Thread.new(i) do
|
18
|
+
sleep(0.2)
|
17
19
|
@article.update_attribute :karma, (@article.karma + 1)
|
18
20
|
end
|
19
21
|
end
|
@@ -22,4 +24,41 @@ describe "check atomicity" do
|
|
22
24
|
|
23
25
|
Article.first.karma.should == 51
|
24
26
|
end
|
27
|
+
=end
|
28
|
+
it "should properly increment property's value" do
|
29
|
+
threads = []
|
30
|
+
|
31
|
+
50.times do |i|
|
32
|
+
id = i
|
33
|
+
threads << Thread.new(i) do
|
34
|
+
if id % 2 == 0
|
35
|
+
art = Article.create :title => "article ##{id}", :karma => id
|
36
|
+
puts "article.last.id - #{art.id}, article.last.karma - #{art.karma}"
|
37
|
+
else
|
38
|
+
puts "id - #{id}, (id / 2) + 1 - #{(id / 2) + 1}"
|
39
|
+
Article.find((id / 2) + 1).destroy
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
threads.each{|thread| thread.join}
|
45
|
+
Article.count.should == 0
|
46
|
+
end
|
47
|
+
=begin
|
48
|
+
it "should properly increment/decrement property's value" do
|
49
|
+
article = Article.create :title => "article #1", :karma => 10
|
50
|
+
threads = []
|
51
|
+
|
52
|
+
10.times do
|
53
|
+
threads << Thread.new{ article.update_attribute(:karma, (article.karma + 2)) }
|
54
|
+
end
|
55
|
+
|
56
|
+
15.times do
|
57
|
+
threads << Thread.new{ article.update_attribute(:karma, (article.karma - 1)) }
|
58
|
+
end
|
59
|
+
|
60
|
+
threads.each{|thread| thread.join}
|
61
|
+
article.karma.should == 15
|
62
|
+
end
|
63
|
+
=end
|
25
64
|
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require File.dirname(File.expand_path(__FILE__)) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class User < RedisOrm::Base
|
4
|
+
use_uuid_as_id
|
5
|
+
|
6
|
+
property :name, String
|
7
|
+
property :age, Integer
|
8
|
+
property :wage, Float
|
9
|
+
property :male, RedisOrm::Boolean
|
10
|
+
|
11
|
+
property :created_at, Time
|
12
|
+
property :modified_at, Time
|
13
|
+
|
14
|
+
has_many :users, :as => :friends
|
15
|
+
end
|
16
|
+
|
17
|
+
class DefaultUser < RedisOrm::Base
|
18
|
+
use_uuid_as_id
|
19
|
+
|
20
|
+
property :name, String, :default => "german"
|
21
|
+
property :age, Integer, :default => 26
|
22
|
+
property :wage, Float, :default => 256.25
|
23
|
+
property :male, RedisOrm::Boolean, :default => true
|
24
|
+
property :admin, RedisOrm::Boolean, :default => false
|
25
|
+
|
26
|
+
property :created_at, Time
|
27
|
+
property :modified_at, Time
|
28
|
+
end
|
29
|
+
|
30
|
+
class TimeStamp < RedisOrm::Base
|
31
|
+
use_uuid_as_id
|
32
|
+
timestamps
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "check basic functionality" do
|
36
|
+
it "test_simple_creation" do
|
37
|
+
User.count.should == 0
|
38
|
+
|
39
|
+
user = User.new :name => "german"
|
40
|
+
user.save
|
41
|
+
|
42
|
+
user.should be
|
43
|
+
user.id.should be
|
44
|
+
|
45
|
+
user.id.should_not == 1
|
46
|
+
user.id.length.should == 32 # b57525b09a69012e8fbe001d61192f09 for example
|
47
|
+
|
48
|
+
user.name.should == "german"
|
49
|
+
|
50
|
+
User.count.should == 1
|
51
|
+
User.first.name.should == "german"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should test different ways to update a record" do
|
55
|
+
User.count.should == 0
|
56
|
+
|
57
|
+
user = User.new :name => "german"
|
58
|
+
user.should be
|
59
|
+
user.save
|
60
|
+
|
61
|
+
user.name.should == "german"
|
62
|
+
|
63
|
+
user.name = "nobody"
|
64
|
+
user.save
|
65
|
+
|
66
|
+
User.count.should == 1
|
67
|
+
User.first.name.should == "nobody"
|
68
|
+
|
69
|
+
u = User.first
|
70
|
+
u.should be
|
71
|
+
u.id.should_not == 1
|
72
|
+
u.id.length.should == 32
|
73
|
+
u.update_attribute :name, "root"
|
74
|
+
User.first.name.should == "root"
|
75
|
+
|
76
|
+
u = User.first
|
77
|
+
u.should be
|
78
|
+
u.update_attributes :name => "german"
|
79
|
+
User.first.name.should == "german"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "test_deletion" do
|
83
|
+
User.count.should == 0
|
84
|
+
|
85
|
+
user = User.new :name => "german"
|
86
|
+
user.save
|
87
|
+
user.should be
|
88
|
+
|
89
|
+
user.name.should == "german"
|
90
|
+
|
91
|
+
User.count.should == 1
|
92
|
+
id = user.id
|
93
|
+
|
94
|
+
user.destroy
|
95
|
+
User.count.should == 0
|
96
|
+
$redis.zrank("user:ids", id).should == nil
|
97
|
+
$redis.hgetall("user:#{id}").should == {}
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should return first and last objects" do
|
101
|
+
User.count.should == 0
|
102
|
+
User.first.should == nil
|
103
|
+
User.last.should == nil
|
104
|
+
|
105
|
+
user1 = User.new :name => "german"
|
106
|
+
user1.save
|
107
|
+
user1.should be
|
108
|
+
user1.name.should == "german"
|
109
|
+
user1.id.should_not == 1
|
110
|
+
user1.id.length.should == 32 # b57525b09a69012e8fbe001d61192f09 for example
|
111
|
+
|
112
|
+
user2 = User.new :name => "nobody"
|
113
|
+
user2.save
|
114
|
+
user2.should be
|
115
|
+
user2.name.should == "nobody"
|
116
|
+
user2.id.should_not == 2
|
117
|
+
user2.id.length.should == 32
|
118
|
+
|
119
|
+
User.count.should == 2
|
120
|
+
|
121
|
+
User.first.should be
|
122
|
+
User.last.should be
|
123
|
+
|
124
|
+
User.first.id.should == user1.id
|
125
|
+
User.last.id.should == user2.id
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should return values with correct classes" do
|
129
|
+
user = User.new
|
130
|
+
user.name = "german"
|
131
|
+
user.age = 26
|
132
|
+
user.wage = 124.34
|
133
|
+
user.male = true
|
134
|
+
user.save
|
135
|
+
|
136
|
+
user.should be
|
137
|
+
|
138
|
+
u = User.first
|
139
|
+
|
140
|
+
u.created_at.class.should == Time
|
141
|
+
u.modified_at.class.should == Time
|
142
|
+
u.wage.class.should == Float
|
143
|
+
u.male.class.to_s.should match(/TrueClass|FalseClass/)
|
144
|
+
u.age.class.to_s.should match(/Integer|Fixnum/)
|
145
|
+
u.id.should_not == 1
|
146
|
+
u.id.length.should == 32
|
147
|
+
|
148
|
+
u.name.should == "german"
|
149
|
+
u.wage.should == 124.34
|
150
|
+
u.age.should == 26
|
151
|
+
u.male.should == true
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should return correct saved defaults" do
|
155
|
+
DefaultUser.count.should == 0
|
156
|
+
DefaultUser.create
|
157
|
+
DefaultUser.count.should == 1
|
158
|
+
|
159
|
+
u = DefaultUser.first
|
160
|
+
|
161
|
+
u.created_at.class.should == Time
|
162
|
+
u.modified_at.class.should == Time
|
163
|
+
u.wage.class.should == Float
|
164
|
+
u.male.class.to_s.should match(/TrueClass|FalseClass/)
|
165
|
+
u.admin.class.to_s.should match(/TrueClass|FalseClass/)
|
166
|
+
u.age.class.to_s.should match(/Integer|Fixnum/)
|
167
|
+
|
168
|
+
u.name.should == "german"
|
169
|
+
u.male.should == true
|
170
|
+
u.age.should == 26
|
171
|
+
u.wage.should == 256.25
|
172
|
+
u.admin.should == false
|
173
|
+
u.id.should_not == 1
|
174
|
+
u.id.length.should == 32
|
175
|
+
|
176
|
+
du = DefaultUser.new
|
177
|
+
du.name = "germaninthetown"
|
178
|
+
du.save
|
179
|
+
|
180
|
+
du_saved = DefaultUser.last
|
181
|
+
du_saved.name.should == "germaninthetown"
|
182
|
+
du_saved.admin.should == false
|
183
|
+
du.id.should_not == 2
|
184
|
+
du.id.should_not == u.id
|
185
|
+
du.id.length.should == 32
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should expand timestamps declaration properly" do
|
189
|
+
t = TimeStamp.new
|
190
|
+
t.save
|
191
|
+
|
192
|
+
t.created_at.should be
|
193
|
+
t.modified_at.should be
|
194
|
+
t.created_at.day.should == Time.now.day
|
195
|
+
t.modified_at.day.should == Time.now.day
|
196
|
+
end
|
197
|
+
|
198
|
+
# from associations_test.rb
|
199
|
+
it "should maintain correct self referencing link" do
|
200
|
+
me = User.create :name => "german", :age => 26, :wage => 10.0, :male => true
|
201
|
+
friend1 = User.create :name => "friend1", :age => 26, :wage => 7.0, :male => true
|
202
|
+
friend2 = User.create :name => "friend2", :age => 25, :wage => 5.0, :male => true
|
203
|
+
|
204
|
+
me.friends << [friend1, friend2]
|
205
|
+
|
206
|
+
me.friends.count.should == 2
|
207
|
+
friend1.friends.count.should == 0
|
208
|
+
friend2.friends.count.should == 0
|
209
|
+
end
|
210
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis_orm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.5.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-07-
|
12
|
+
date: 2011-07-27 00:00:00.000000000 +03:00
|
13
|
+
default_executable:
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: activesupport
|
16
|
-
requirement: &
|
17
|
+
requirement: &87829630 !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ! '>='
|
@@ -21,10 +22,10 @@ dependencies:
|
|
21
22
|
version: 3.0.0
|
22
23
|
type: :runtime
|
23
24
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
+
version_requirements: *87829630
|
25
26
|
- !ruby/object:Gem::Dependency
|
26
27
|
name: activemodel
|
27
|
-
requirement: &
|
28
|
+
requirement: &87829290 !ruby/object:Gem::Requirement
|
28
29
|
none: false
|
29
30
|
requirements:
|
30
31
|
- - ! '>='
|
@@ -32,10 +33,10 @@ dependencies:
|
|
32
33
|
version: 3.0.0
|
33
34
|
type: :runtime
|
34
35
|
prerelease: false
|
35
|
-
version_requirements: *
|
36
|
+
version_requirements: *87829290
|
36
37
|
- !ruby/object:Gem::Dependency
|
37
38
|
name: redis
|
38
|
-
requirement: &
|
39
|
+
requirement: &87828950 !ruby/object:Gem::Requirement
|
39
40
|
none: false
|
40
41
|
requirements:
|
41
42
|
- - ! '>='
|
@@ -43,10 +44,21 @@ dependencies:
|
|
43
44
|
version: 2.2.0
|
44
45
|
type: :runtime
|
45
46
|
prerelease: false
|
46
|
-
version_requirements: *
|
47
|
+
version_requirements: *87828950
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: uuid
|
50
|
+
requirement: &87828600 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 2.3.2
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *87828600
|
47
59
|
- !ruby/object:Gem::Dependency
|
48
60
|
name: rspec
|
49
|
-
requirement: &
|
61
|
+
requirement: &87828250 !ruby/object:Gem::Requirement
|
50
62
|
none: false
|
51
63
|
requirements:
|
52
64
|
- - ! '>='
|
@@ -54,7 +66,7 @@ dependencies:
|
|
54
66
|
version: 2.5.0
|
55
67
|
type: :development
|
56
68
|
prerelease: false
|
57
|
-
version_requirements: *
|
69
|
+
version_requirements: *87828250
|
58
70
|
description: ORM for Redis (advanced key-value storage) with ActiveRecord API
|
59
71
|
email: germaninthetown@gmail.com
|
60
72
|
executables: []
|
@@ -100,7 +112,9 @@ files:
|
|
100
112
|
- test/polymorphic_test.rb
|
101
113
|
- test/redis.conf
|
102
114
|
- test/test_helper.rb
|
115
|
+
- test/uuid_as_id_test.rb
|
103
116
|
- test/validations_test.rb
|
117
|
+
has_rdoc: true
|
104
118
|
homepage: https://github.com/german/redis_orm
|
105
119
|
licenses: []
|
106
120
|
post_install_message:
|
@@ -127,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
141
|
version: '1.2'
|
128
142
|
requirements: []
|
129
143
|
rubyforge_project: redis_orm
|
130
|
-
rubygems_version: 1.
|
144
|
+
rubygems_version: 1.6.2
|
131
145
|
signing_key:
|
132
146
|
specification_version: 3
|
133
147
|
summary: ORM for Redis (advanced key-value storage) with ActiveRecord API
|
@@ -138,6 +152,7 @@ test_files:
|
|
138
152
|
- test/validations_test.rb
|
139
153
|
- test/test_helper.rb
|
140
154
|
- test/polymorphic_test.rb
|
155
|
+
- test/uuid_as_id_test.rb
|
141
156
|
- test/atomicity_test.rb
|
142
157
|
- test/exceptions_test.rb
|
143
158
|
- test/association_indices_test.rb
|