redis_orm 0.1

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.
data/redis_orm.gemspec ADDED
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{redis_orm}
5
+ s.version = "0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Dmitrii Samoilov"]
9
+ s.date = %q{2011-06-02}
10
+ s.description = %q{ORM for Redis advanced key-value storage}
11
+ s.email = %q{germaninthetown@gmail.com}
12
+ s.extra_rdoc_files = ["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_proxy.rb", "lib/redis_orm/associations/has_one.rb", "lib/redis_orm/redis_orm.rb"]
13
+ s.files = ["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_proxy.rb", "lib/redis_orm/associations/has_one.rb", "lib/redis_orm/redis_orm.rb", "redis_orm.gemspec", "test/associations_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/redis.conf", "test/validations_test.rb"]
14
+ s.homepage = %q{https://github.com/german/redis_orm}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Redis_orm", "--main", "README.md"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{redis_orm}
18
+ s.rubygems_version = %q{1.6.2}
19
+ s.summary = %q{ORM for Redis advanced key-value storage}
20
+ s.test_files = ["test/options_test.rb", "test/dynamic_finders_test.rb", "test/associations_test.rb", "test/validations_test.rb", "test/exceptions_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
+
22
+ if s.respond_to? :specification_version then
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0"])
27
+ s.add_runtime_dependency(%q<activemodel>, [">= 3.0.0"])
28
+ s.add_runtime_dependency(%q<redis>, [">= 2.2.0"])
29
+ s.add_development_dependency(%q<rspec>, [">= 2.5.0"])
30
+ else
31
+ s.add_dependency(%q<activesupport>, [">= 3.0.0"])
32
+ s.add_dependency(%q<activemodel>, [">= 3.0.0"])
33
+ s.add_dependency(%q<redis>, [">= 2.2.0"])
34
+ s.add_dependency(%q<rspec>, [">= 2.5.0"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<activesupport>, [">= 3.0.0"])
38
+ s.add_dependency(%q<activemodel>, [">= 3.0.0"])
39
+ s.add_dependency(%q<redis>, [">= 2.2.0"])
40
+ s.add_dependency(%q<rspec>, [">= 2.5.0"])
41
+ end
42
+ end
@@ -0,0 +1,226 @@
1
+ require 'rspec'
2
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/redis_orm.rb'
3
+
4
+ class Article < RedisOrm::Base
5
+ property :title, String
6
+ has_many :comments
7
+ has_many :categories
8
+ end
9
+
10
+ class Comment < RedisOrm::Base
11
+ property :body, String
12
+ belongs_to :article
13
+ end
14
+
15
+ class Profile < RedisOrm::Base
16
+ property :title, String
17
+ has_one :city
18
+ end
19
+
20
+ class City < RedisOrm::Base
21
+ property :name, String
22
+ has_many :profiles
23
+ end
24
+
25
+ class Category < RedisOrm::Base
26
+ property :name, String
27
+ has_many :articles
28
+ end
29
+
30
+ class User < RedisOrm::Base
31
+ property :name, String
32
+ index :name
33
+ has_many :users, :as => :friends
34
+ end
35
+
36
+ describe "check associations" do
37
+ before(:all) do
38
+ path_to_conf = File.dirname(File.expand_path(__FILE__)) + "/redis.conf"
39
+ $redis_pid = spawn 'redis-server ' + path_to_conf, :out => "/dev/null"
40
+ sleep(0.3) # must be some delay otherwise "Connection refused - Unable to connect to Redis"
41
+ path_to_socket = File.dirname(File.expand_path(__FILE__)) + "/../redis.sock"
42
+ $redis = Redis.new(:host => 'localhost', :path => path_to_socket)
43
+ end
44
+
45
+ before(:each) do
46
+ $redis.flushall if $redis
47
+ @article = Article.new
48
+ @article.title = "DHH drops OpenID on 37signals"
49
+ @article.save
50
+
51
+ @article.should be
52
+ @article.title.should == "DHH drops OpenID on 37signals"
53
+
54
+ @comment1 = Comment.new
55
+ @comment1.body = "test"
56
+ @comment1.save
57
+ @comment1.should be
58
+ @comment1.body.should == "test"
59
+
60
+ @comment2 = Comment.new
61
+ @comment2.body = "test #2"
62
+ @comment2.save
63
+ @comment2.should be
64
+ @comment2.body.should == "test #2"
65
+ end
66
+
67
+ after(:each) do
68
+ $redis.flushall if $redis
69
+ end
70
+
71
+ after(:all) do
72
+ Process.kill 9, $redis_pid.to_i if $redis_pid
73
+ end
74
+
75
+ it "should return array" do
76
+ @article.comments << [@comment1, @comment2]
77
+ #@article.comments.should be_kind_of(Array)
78
+
79
+ @article.comments.count.should == 2
80
+ @article.comments.size.should == 2
81
+
82
+ @comment1.article.should be
83
+ @comment2.article.should be
84
+
85
+ @comment1.article.id.should == @comment2.article.id
86
+ end
87
+
88
+ it "should return 1 comment when second was deleted" do
89
+ Comment.count.should == 2
90
+ @article.comments << [@comment1, @comment2]
91
+ #@article.comments.should be_kind_of(Array)
92
+ @article.comments.size.should == 2
93
+
94
+ @comment1.destroy
95
+
96
+ @article.comments.size.should == 1
97
+ @article.comments.count.should == 1
98
+ Comment.count.should == 1
99
+ end
100
+
101
+ it "should leave associations when parent has been deleted (nullify assocs)" do
102
+ Comment.count.should == 2
103
+ @article.comments << [@comment1, @comment2]
104
+ @comment1.article.id.should == @article.id
105
+ @comment2.article.id.should == @article.id
106
+ #@article.comments.should be_kind_of(Array)
107
+ @article.comments.size.should == 2
108
+ @article.comments.count.should == 2
109
+
110
+ @article.destroy
111
+
112
+ Article.count.should == 0
113
+
114
+ Comment.count.should == 2
115
+ end
116
+
117
+ it "should replace associations when '=' is used instead of '<<' " do
118
+ Comment.count.should == 2
119
+ @article.comments << [@comment1, @comment2]
120
+ @comment1.article.id.should == @article.id
121
+ @comment2.article.id.should == @article.id
122
+ @article.comments.size.should == 2
123
+ @article.comments.count.should == 2
124
+
125
+ @article.comments = [@comment1]
126
+ @article.comments.count.should == 1
127
+ @article.comments.first.id.should == @comment1.id
128
+
129
+ @comment1.article.id.should == @article.id
130
+ end
131
+
132
+ it "should correctly use many-to-many associations both with '=' and '<<' " do
133
+ @cat1 = Category.create :name => "Nature"
134
+ @cat2 = Category.create :name => "Art"
135
+ @cat3 = Category.create :name => "Web"
136
+
137
+ @cat1.name.should == "Nature"
138
+ @cat2.name.should == "Art"
139
+ @cat3.name.should == "Web"
140
+
141
+ @article.categories << [@cat1, @cat2]
142
+
143
+ @cat1.articles.count.should == 1
144
+ @cat1.articles[0].id.should == @article.id
145
+ @cat2.articles.count.should == 1
146
+ @cat2.articles[0].id.should == @article.id
147
+
148
+ @article.categories.size.should == 2
149
+ @article.categories.count.should == 2
150
+
151
+ @article.categories = [@cat1, @cat3]
152
+ @article.categories.count.should == 2
153
+ @article.categories.map{|c| c.id}.include?(@cat1.id).should be
154
+ @article.categories.map{|c| c.id}.include?(@cat3.id).should be
155
+
156
+ @cat1.articles.count.should == 1
157
+ @cat1.articles[0].id.should == @article.id
158
+
159
+ @cat3.articles.count.should == 1
160
+ @cat3.articles[0].id.should == @article.id
161
+
162
+ @cat2.articles.count.should == 0
163
+
164
+ @cat1.destroy
165
+ Category.count.should == 2
166
+ @article.categories.count.should == 1
167
+ end
168
+
169
+ it "should remove old associations and create new ones" do
170
+ profile = Profile.new
171
+ profile.title = "test"
172
+ profile.save
173
+
174
+ chicago = City.new
175
+ chicago.name = "Chicago"
176
+ chicago.save
177
+
178
+ washington = City.new
179
+ washington.name = "Washington"
180
+ washington.save
181
+
182
+ profile.city = chicago
183
+ profile.city.name.should == "Chicago"
184
+ chicago.profiles.count.should == 1
185
+ washington.profiles.count.should == 0
186
+ chicago.profiles[0].id.should == profile.id
187
+
188
+ profile.city = washington
189
+ profile.city.name.should == "Washington"
190
+ chicago.profiles.count.should == 0
191
+ washington.profiles.count.should == 1
192
+ washington.profiles[0].id.should == profile.id
193
+ end
194
+
195
+ it "should maintain correct self referencing link" do
196
+ me = User.create :name => "german"
197
+ friend1 = User.create :name => "friend1"
198
+ friend2 = User.create :name => "friend2"
199
+
200
+ me.friends << [friend1, friend2]
201
+
202
+ me.friends.count.should == 2
203
+ friend1.friends.count.should == 0
204
+ friend2.friends.count.should == 0
205
+ end
206
+
207
+ it "should delete one specific record from an array with associated records" do
208
+ me = User.create :name => "german"
209
+ friend1 = User.create :name => "friend1"
210
+ friend2 = User.create :name => "friend2"
211
+
212
+ me.friends << [friend1, friend2]
213
+
214
+ me = User.find_by_name 'german'
215
+ me.friends.count.should == 2
216
+ friend1 = User.find_by_name 'friend1'
217
+ friend1.friends.count.should == 0
218
+ friend2 = User.find_by_name 'friend2'
219
+ friend2.friends.count.should == 0
220
+
221
+ me.friends.delete(friend1.id)
222
+ me.friends.count.should == 1
223
+ me.friends[0].id == friend2.id
224
+ User.count.should == 3
225
+ end
226
+ end
@@ -0,0 +1,166 @@
1
+ require 'rspec'
2
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/redis_orm.rb'
3
+
4
+ class User < RedisOrm::Base
5
+ property :name, String
6
+ property :age, Integer
7
+ property :wage, Float
8
+ property :male, RedisOrm::Boolean
9
+
10
+ property :created_at, Time
11
+ property :modified_at, Time
12
+ end
13
+
14
+ class DefaultUser < RedisOrm::Base
15
+ property :name, String, :default => "german"
16
+ property :age, Integer, :default => 26
17
+ property :wage, Float, :default => 256.25
18
+ property :male, RedisOrm::Boolean, :default => true
19
+
20
+ property :created_at, Time
21
+ property :modified_at, Time
22
+ end
23
+
24
+ describe "check basic functionality" do
25
+ before(:all) do
26
+ path_to_conf = File.dirname(File.expand_path(__FILE__)) + "/redis.conf"
27
+ $redis_pid = spawn 'redis-server ' + path_to_conf, :out => "/dev/null"
28
+ sleep(0.3) # must be some delay otherwise "Connection refused - Unable to connect to Redis"
29
+ path_to_socket = File.dirname(File.expand_path(__FILE__)) + "/../redis.sock"
30
+ $redis = Redis.new(:host => 'localhost', :path => path_to_socket)
31
+ end
32
+
33
+ before(:each) do
34
+ $redis.flushall if $redis
35
+ end
36
+
37
+ after(:each) do
38
+ $redis.flushall if $redis
39
+ end
40
+
41
+ after(:all) do
42
+ Process.kill 9, $redis_pid.to_i if $redis_pid
43
+ end
44
+
45
+ it "test_simple_creation" do
46
+ User.count.should == 0
47
+
48
+ user = User.new :name => "german"
49
+ user.save
50
+
51
+ user.should be
52
+
53
+ user.name.should == "german"
54
+
55
+ User.count.should == 1
56
+ User.first.name.should == "german"
57
+ end
58
+
59
+ it "should test different ways to update a record" do
60
+ User.count.should == 0
61
+
62
+ user = User.new :name => "german"
63
+ user.should be
64
+ user.save
65
+
66
+ user.name.should == "german"
67
+
68
+ user.name = "nobody"
69
+ user.save
70
+
71
+ User.count.should == 1
72
+ User.first.name.should == "nobody"
73
+
74
+ u = User.first
75
+ u.should be
76
+ u.update_attribute :name, "root"
77
+ User.first.name.should == "root"
78
+
79
+ u = User.first
80
+ u.should be
81
+ u.update_attributes :name => "german"
82
+ User.first.name.should == "german"
83
+ end
84
+
85
+ it "test_deletion" do
86
+ User.count.should == 0
87
+
88
+ user = User.new :name => "german"
89
+ user.save
90
+ user.should be
91
+
92
+ user.name.should == "german"
93
+
94
+ User.count.should == 1
95
+
96
+ user.destroy
97
+ User.count.should == 0
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
+
110
+ user2 = User.new :name => "nobody"
111
+ user2.save
112
+ user2.should be
113
+ user2.name.should == "nobody"
114
+
115
+ User.count.should == 2
116
+
117
+ User.first.should be
118
+ User.last.should be
119
+
120
+ User.first.id.should == user1.id
121
+ User.last.id.should == user2.id
122
+ end
123
+
124
+ it "should return values with correct classes" do
125
+ user = User.new
126
+ user.name = "german"
127
+ user.age = 26
128
+ user.wage = 124.34
129
+ user.male = true
130
+ user.save
131
+
132
+ user.should be
133
+
134
+ u = User.first
135
+
136
+ u.created_at.class.should == Time
137
+ u.modified_at.class.should == Time
138
+ u.wage.class.should == Float
139
+ u.male.class.to_s.should match(/TrueClass|FalseClass/)
140
+ u.age.class.to_s.should match(/Integer|Fixnum/)
141
+
142
+ u.name.should == "german"
143
+ u.wage.should == 124.34
144
+ u.age.should == 26
145
+ u.male.should == true
146
+ end
147
+
148
+ it "should return correct saved defaults" do
149
+ DefaultUser.count.should == 0
150
+ DefaultUser.create
151
+ DefaultUser.count.should == 1
152
+
153
+ u = DefaultUser.first
154
+
155
+ u.created_at.class.should == Time
156
+ u.modified_at.class.should == Time
157
+ u.wage.class.should == Float
158
+ u.male.class.to_s.should match(/TrueClass|FalseClass/)
159
+ u.age.class.to_s.should match(/Integer|Fixnum/)
160
+
161
+ u.name.should == "german"
162
+ u.male.should == true
163
+ u.age.should == 26
164
+ u.wage.should == 256.25
165
+ end
166
+ end
@@ -0,0 +1,140 @@
1
+ require 'rspec'
2
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/redis_orm.rb'
3
+
4
+ class CutoutAggregator < RedisOrm::Base
5
+ property :modified_at, Time
6
+
7
+ property :revision, Integer, :default => 0
8
+ end
9
+
10
+ class Cutout < RedisOrm::Base
11
+ property :filename, String
12
+
13
+ before_create :increase_revisions
14
+ before_destroy :decrease_revisions
15
+
16
+ def increase_revisions
17
+ ca = CutoutAggregator.last
18
+ ca.update_attribute(:revision, ca.revision + 1) if ca
19
+ end
20
+
21
+ def decrease_revisions
22
+ ca = CutoutAggregator.first
23
+ if ca.revision > 0
24
+ ca.update_attribute :revision, ca.revision - 1
25
+ end
26
+
27
+ ca.destroy if ca.revision == 0
28
+ end
29
+ end
30
+
31
+ class Comment < RedisOrm::Base
32
+ property :text, String
33
+
34
+ belongs_to :user
35
+
36
+ before_save :trim_whitespaces
37
+ after_save :regenerate_karma
38
+
39
+ def trim_whitespaces
40
+ self.text = self.text.strip
41
+ end
42
+
43
+ def regenerate_karma
44
+ if self.user
45
+ self.user.update_attribute :karma, (self.user.karma - self.text.length)
46
+ end
47
+ end
48
+ end
49
+
50
+ class User < RedisOrm::Base
51
+ property :first_name, String
52
+ property :last_name, String
53
+
54
+ property :karma, Integer, :default => 1000
55
+
56
+ index :first_name
57
+ index :last_name
58
+ index [:first_name, :last_name]
59
+
60
+ has_many :comments
61
+
62
+ after_create :store_in_rating
63
+ after_destroy :after_destroy_callback
64
+
65
+ def store_in_rating
66
+ $redis.zadd "users:sorted_by_rating", 0.0, self.id
67
+ end
68
+
69
+ def after_destroy_callback
70
+ self.comments.map{|c| c.destroy}
71
+ end
72
+ end
73
+
74
+ describe "check callbacks" do
75
+ before(:all) do
76
+ path_to_conf = File.dirname(File.expand_path(__FILE__)) + "/redis.conf"
77
+ $redis_pid = spawn 'redis-server ' + path_to_conf, :out => "/dev/null"
78
+ sleep(0.3) # must be some delay otherwise "Connection refused - Unable to connect to Redis"
79
+ path_to_socket = File.dirname(File.expand_path(__FILE__)) + "/../redis.sock"
80
+ $redis = Redis.new(:host => 'localhost', :path => path_to_socket)
81
+ end
82
+
83
+ before(:each) do
84
+ $redis.flushall if $redis
85
+ end
86
+
87
+ after(:each) do
88
+ $redis.flushall if $redis
89
+ end
90
+
91
+ after(:all) do
92
+ Process.kill 9, $redis_pid.to_i if $redis_pid
93
+ end
94
+
95
+ it "should fire after_create/after_destroy callbacks" do
96
+ user = User.new :first_name => "Robert", :last_name => "Pirsig"
97
+ user.save
98
+
99
+ $redis.zrank("users:sorted_by_rating", user.id).should == 0
100
+
101
+ comment = Comment.create :text => "First!"
102
+ user.comments << comment
103
+
104
+ u = User.first
105
+ u.id.should == user.id
106
+ u.comments.count.should == 1
107
+ u.destroy
108
+ u.comments.count.should == 0
109
+ end
110
+
111
+ it "should fire before_create/before_destroy callbacks" do
112
+ CutoutAggregator.create
113
+
114
+ CutoutAggregator.count.should == 1
115
+ Cutout.create :filename => "1.jpg"
116
+ Cutout.create :filename => "2.jpg"
117
+ CutoutAggregator.last.revision.should == 2
118
+ Cutout.last.destroy
119
+ Cutout.last.destroy
120
+ CutoutAggregator.count.should == 0
121
+ end
122
+
123
+ it "should fire after_save/before_save callbacks" do
124
+ comment = Comment.new :text => " Trim meeee ! "
125
+ comment.save
126
+ Comment.first.text.should == "Trim meeee !"
127
+
128
+ user = User.new :first_name => "Robert", :last_name => "Pirsig"
129
+ user.save
130
+ user.karma.should == 1000
131
+
132
+ user.comments << comment
133
+ user.comments.count == 1
134
+
135
+ c = Comment.first
136
+ c.update_attributes :text => "Another brick in the wall"
137
+
138
+ User.first.karma.should == 975
139
+ end
140
+ end