simply_stored 0.1.14 → 0.1.15
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/CHANGELOG.md +27 -0
- data/README.md +6 -0
- data/lib/simply_stored/couch/has_many.rb +49 -16
- data/lib/simply_stored/couch.rb +3 -0
- data/lib/simply_stored/instance_methods.rb +7 -2
- data/test/simply_stored_couch_test.rb +88 -5
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,33 @@
|
|
1
1
|
Changelog
|
2
2
|
=============
|
3
3
|
|
4
|
+
- Support :order option to has_many associations and classes, e.g:
|
5
|
+
|
6
|
+
@user.posts(:order => :desc)
|
7
|
+
Post.find(:all, :order => :desc)
|
8
|
+
|
9
|
+
Default to the CouchDB default of ascending.
|
10
|
+
|
11
|
+
|
12
|
+
- Support :limit option to has_many and has_many :through associations, e.g:
|
13
|
+
|
14
|
+
@user.posts(:limit => 5)
|
15
|
+
|
16
|
+
0.1.14
|
17
|
+
=============
|
18
|
+
|
19
|
+
- Add ability to delete all design documents:
|
20
|
+
|
21
|
+
SimplyStored::Couch.delete_all_design_documents('http://localhost:5984/mydbname')
|
22
|
+
|
23
|
+
- Add rake tasks to delete all design documents. In your Rakefile:
|
24
|
+
|
25
|
+
require 'simply_stored/rake'
|
26
|
+
|
27
|
+
Then you can delete all design documents in a database like this:
|
28
|
+
|
29
|
+
DATABASE=http://localhost:5984/mydb rake simply_stored:delete_design_documents
|
30
|
+
|
4
31
|
0.1.13
|
5
32
|
=============
|
6
33
|
|
data/README.md
CHANGED
@@ -119,6 +119,12 @@ The supported associations are: belongs_to, has_one, has_many, and has_many :thr
|
|
119
119
|
post.comments
|
120
120
|
# => [mikes_comment, johns_comment]
|
121
121
|
|
122
|
+
post.comments(:order => :desc)
|
123
|
+
# => [johns_comment, mikes_comment]
|
124
|
+
|
125
|
+
post.comments(:limit => 1)
|
126
|
+
# => [mikes_comment]
|
127
|
+
|
122
128
|
post.comment_count
|
123
129
|
# => 2
|
124
130
|
|
@@ -9,18 +9,25 @@ module SimplyStored
|
|
9
9
|
define_method(name) do |*args|
|
10
10
|
options = args.first && args.first.is_a?(Hash) && args.first
|
11
11
|
if options
|
12
|
-
options.assert_valid_keys(:force_reload, :with_deleted)
|
13
|
-
forced_reload = options
|
12
|
+
options.assert_valid_keys(:force_reload, :with_deleted, :limit, :order)
|
13
|
+
forced_reload = options.delete(:force_reload)
|
14
14
|
with_deleted = options[:with_deleted]
|
15
|
+
limit = options[:limit]
|
16
|
+
descending = (options[:order] == :desc) ? true : false
|
15
17
|
else
|
16
18
|
forced_reload = false
|
17
19
|
with_deleted = false
|
20
|
+
limit = nil
|
21
|
+
descending = false
|
18
22
|
end
|
19
23
|
|
20
|
-
|
21
|
-
|
24
|
+
cached_results = cached_results = send("_get_cached_#{name}")
|
25
|
+
cache_key = _cache_key_for(options)
|
26
|
+
if forced_reload || cached_results[cache_key].nil?
|
27
|
+
cached_results[cache_key] = find_associated(name, self.class, :with_deleted => with_deleted, :limit => limit, :descending => descending)
|
28
|
+
instance_variable_set("@#{name}", cached_results)
|
22
29
|
end
|
23
|
-
|
30
|
+
cached_results[cache_key]
|
24
31
|
end
|
25
32
|
end
|
26
33
|
|
@@ -30,26 +37,31 @@ module SimplyStored
|
|
30
37
|
define_method(name) do |*args|
|
31
38
|
options = args.first && args.first.is_a?(Hash) && args.first
|
32
39
|
if options
|
33
|
-
options.assert_valid_keys(:force_reload, :with_deleted)
|
40
|
+
options.assert_valid_keys(:force_reload, :with_deleted, :limit)
|
34
41
|
forced_reload = options[:force_reload]
|
35
42
|
with_deleted = options[:with_deleted]
|
43
|
+
limit = options[:limit]
|
36
44
|
else
|
37
45
|
forced_reload = false
|
38
46
|
with_deleted = false
|
47
|
+
limit = nil
|
39
48
|
end
|
40
49
|
|
41
|
-
|
50
|
+
cached_results = send("_get_cached_#{name}")
|
51
|
+
cache_key = _cache_key_for(options)
|
52
|
+
|
53
|
+
if forced_reload || cached_results[cache_key].nil?
|
42
54
|
|
43
55
|
# there is probably a faster way to query this
|
44
|
-
intermediate_objects = find_associated(through, self.class, :with_deleted => with_deleted)
|
56
|
+
intermediate_objects = find_associated(through, self.class, :with_deleted => with_deleted, :limit => limit)
|
45
57
|
|
46
58
|
through_objects = intermediate_objects.map do |intermediate_object|
|
47
59
|
intermediate_object.send(name.to_s.singularize.underscore, :with_deleted => with_deleted)
|
48
60
|
end.flatten.uniq
|
49
|
-
|
50
|
-
instance_variable_set("@#{name}",
|
61
|
+
cached_results[cache_key] = through_objects
|
62
|
+
instance_variable_set("@#{name}", cached_results)
|
51
63
|
end
|
52
|
-
|
64
|
+
cached_results[cache_key]
|
53
65
|
end
|
54
66
|
end
|
55
67
|
|
@@ -59,9 +71,11 @@ module SimplyStored
|
|
59
71
|
raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
|
60
72
|
|
61
73
|
value.send("#{self.class.foreign_key}=", id)
|
62
|
-
value.save
|
63
|
-
|
64
|
-
|
74
|
+
value.save(false)
|
75
|
+
|
76
|
+
cached_results = send("_get_cached_#{name}")[:all]
|
77
|
+
send("_set_cached_#{name}", (cached_results || []) << value, :all)
|
78
|
+
nil
|
65
79
|
end
|
66
80
|
end
|
67
81
|
|
@@ -78,8 +92,9 @@ module SimplyStored
|
|
78
92
|
value.save
|
79
93
|
end
|
80
94
|
|
81
|
-
|
82
|
-
|
95
|
+
cached_results = send("_get_cached_#{name}")[:all]
|
96
|
+
send("_set_cached_#{name}", (cached_results || []).delete_if{|item| item.id == value.id}, :all)
|
97
|
+
nil
|
83
98
|
end
|
84
99
|
end
|
85
100
|
|
@@ -113,6 +128,22 @@ module SimplyStored
|
|
113
128
|
end
|
114
129
|
end
|
115
130
|
|
131
|
+
def define_cache_accessors(name)
|
132
|
+
define_method "_get_cached_#{name}" do
|
133
|
+
instance_variable_get("@#{name}") || {}
|
134
|
+
end
|
135
|
+
|
136
|
+
define_method "_set_cached_#{name}" do |value, cache_key|
|
137
|
+
cached = send("_get_cached_#{name}")
|
138
|
+
cached[cache_key] = value
|
139
|
+
instance_variable_set("@#{name}", cached)
|
140
|
+
end
|
141
|
+
|
142
|
+
define_method "_cache_key_for" do |options|
|
143
|
+
options.blank? ? :all : options.to_s
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
116
147
|
class Property
|
117
148
|
attr_reader :name, :options
|
118
149
|
|
@@ -127,11 +158,13 @@ module SimplyStored
|
|
127
158
|
|
128
159
|
if options[:through]
|
129
160
|
owner_clazz.class_eval do
|
161
|
+
define_cache_accessors(name)
|
130
162
|
define_has_many_through_getter(name, options[:through])
|
131
163
|
define_has_many_count(name, options[:through])
|
132
164
|
end
|
133
165
|
else
|
134
166
|
owner_clazz.class_eval do
|
167
|
+
define_cache_accessors(name)
|
135
168
|
define_has_many_getter(name)
|
136
169
|
define_has_many_setter_add(name)
|
137
170
|
define_has_many_setter_remove(name)
|
data/lib/simply_stored/couch.rb
CHANGED
@@ -50,6 +50,9 @@ module SimplyStored
|
|
50
50
|
def find(*args)
|
51
51
|
what = args.shift
|
52
52
|
options = args.last.is_a?(Hash) ? args.last : {}
|
53
|
+
if options && order = options.delete(:order)
|
54
|
+
options[:descending] = true if order == :desc
|
55
|
+
end
|
53
56
|
|
54
57
|
with_deleted = options.delete(:with_deleted)
|
55
58
|
|
@@ -121,14 +121,19 @@ module SimplyStored
|
|
121
121
|
end
|
122
122
|
|
123
123
|
def find_associated(from, to, options = {})
|
124
|
+
view_options = {}
|
125
|
+
view_options[:reduce] = false
|
126
|
+
view_options[:key] = id
|
127
|
+
view_options[:descending] = options[:descending] if options[:descending]
|
128
|
+
view_options[:limit] = options[:limit] if options[:limit]
|
124
129
|
if options[:with_deleted]
|
125
130
|
CouchPotato.database.view(
|
126
131
|
self.class.get_class_from_name(from).send(
|
127
|
-
"association_#{from.to_s.singularize.underscore}_belongs_to_#{to.name.singularize.underscore}_with_deleted",
|
132
|
+
"association_#{from.to_s.singularize.underscore}_belongs_to_#{to.name.singularize.underscore}_with_deleted", view_options))
|
128
133
|
else
|
129
134
|
CouchPotato.database.view(
|
130
135
|
self.class.get_class_from_name(from).send(
|
131
|
-
"association_#{from.to_s.singularize.underscore}_belongs_to_#{to.name.singularize.underscore}",
|
136
|
+
"association_#{from.to_s.singularize.underscore}_belongs_to_#{to.name.singularize.underscore}", view_options))
|
132
137
|
end
|
133
138
|
end
|
134
139
|
|
@@ -134,11 +134,22 @@ class CouchTest < Test::Unit::TestCase
|
|
134
134
|
|
135
135
|
context "when finding instances" do
|
136
136
|
context "with find(:all)" do
|
137
|
-
|
137
|
+
setup do
|
138
138
|
User.create(:title => "Mr.")
|
139
139
|
User.create(:title => "Mrs.")
|
140
|
+
end
|
141
|
+
|
142
|
+
should "return all instances" do
|
140
143
|
assert_equal 2, User.find(:all).size
|
141
144
|
end
|
145
|
+
|
146
|
+
should "allow a limit" do
|
147
|
+
assert_equal 1, User.find(:all, :limit => 1).size
|
148
|
+
end
|
149
|
+
|
150
|
+
should "allow to order the results" do
|
151
|
+
assert_equal User.find(:all).reverse, User.find(:all, :order => :desc)
|
152
|
+
end
|
142
153
|
end
|
143
154
|
|
144
155
|
context "to find all instances" do
|
@@ -159,6 +170,12 @@ class CouchTest < Test::Unit::TestCase
|
|
159
170
|
assert_equal user, User.first
|
160
171
|
end
|
161
172
|
|
173
|
+
should 'understand the order' do
|
174
|
+
assert_nothing_raised do
|
175
|
+
User.first(:order => :desc)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
162
179
|
should 'return nil when no user found' do
|
163
180
|
assert_nil User.first
|
164
181
|
end
|
@@ -475,6 +492,72 @@ class CouchTest < Test::Unit::TestCase
|
|
475
492
|
user.posts
|
476
493
|
end
|
477
494
|
|
495
|
+
context "limit" do
|
496
|
+
|
497
|
+
should "be able to limit the result set" do
|
498
|
+
user = User.create(:title => "Mr.")
|
499
|
+
3.times {
|
500
|
+
post = Post.new
|
501
|
+
post.user = user
|
502
|
+
post.save!
|
503
|
+
}
|
504
|
+
assert_equal 2, user.posts(:limit => 2).size
|
505
|
+
end
|
506
|
+
|
507
|
+
should "use the given options in the cache-key" do
|
508
|
+
user = User.create(:title => "Mr.")
|
509
|
+
3.times {
|
510
|
+
post = Post.new
|
511
|
+
post.user = user
|
512
|
+
post.save!
|
513
|
+
}
|
514
|
+
assert_equal 2, user.posts(:limit => 2).size
|
515
|
+
assert_equal 3, user.posts(:limit => 3).size
|
516
|
+
end
|
517
|
+
|
518
|
+
should "be able to limit the result set - also for through objects" do
|
519
|
+
@user = User.create(:title => "Mr.")
|
520
|
+
first_pain = Pain.create
|
521
|
+
frist_hemorrhoid = Hemorrhoid.create(:user => @user, :pain => first_pain)
|
522
|
+
assert_equal [first_pain], @user.pains
|
523
|
+
second_pain = Pain.create
|
524
|
+
second_hemorrhoid = Hemorrhoid.create(:user => @user, :pain => second_pain)
|
525
|
+
@user.reload
|
526
|
+
assert_equal 2, @user.pains.size
|
527
|
+
assert_equal 1, @user.pains(:limit => 1).size
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
context "order" do
|
532
|
+
setup do
|
533
|
+
@user = User.create(:title => "Mr.")
|
534
|
+
3.times {
|
535
|
+
post = Post.new
|
536
|
+
post.user = @user
|
537
|
+
post.save!
|
538
|
+
}
|
539
|
+
end
|
540
|
+
|
541
|
+
should "support different order" do
|
542
|
+
assert_nothing_raised do
|
543
|
+
@user.posts(:order => :asc)
|
544
|
+
end
|
545
|
+
|
546
|
+
assert_nothing_raised do
|
547
|
+
@user.posts(:order => :desc)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
should "reverse the order if :desc" do
|
552
|
+
assert_equal @user.posts(:order => :asc).map(&:id).reverse, @user.posts(:order => :desc).map(&:id)
|
553
|
+
end
|
554
|
+
|
555
|
+
should "work with the limit option" do
|
556
|
+
last_post = Post.create(:user => @user)
|
557
|
+
assert_not_equal @user.posts(:order => :asc, :limit => 3).map(&:id).reverse, @user.posts(:order => :desc, :limit => 3).map(&:id)
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
478
561
|
should "verify the given options for the accessor method" do
|
479
562
|
user = User.create(:title => "Mr.")
|
480
563
|
assert_raise(ArgumentError) do
|
@@ -509,7 +592,7 @@ class CouchTest < Test::Unit::TestCase
|
|
509
592
|
post.user = user
|
510
593
|
post.save!
|
511
594
|
user.posts
|
512
|
-
assert_equal [post], user.instance_variable_get("@posts")
|
595
|
+
assert_equal [post], user.instance_variable_get("@posts")[:all]
|
513
596
|
end
|
514
597
|
|
515
598
|
should "add methods to handle associated objects" do
|
@@ -535,7 +618,7 @@ class CouchTest < Test::Unit::TestCase
|
|
535
618
|
assert_equal [], daddy.posts
|
536
619
|
daddy.add_post(item)
|
537
620
|
assert_equal [item], daddy.posts
|
538
|
-
assert_equal [item], daddy.instance_variable_get("@posts")
|
621
|
+
assert_equal [item], daddy.instance_variable_get("@posts")[:all]
|
539
622
|
end
|
540
623
|
|
541
624
|
should "raise an error when the added item is not an object of the expected class" do
|
@@ -575,7 +658,7 @@ class CouchTest < Test::Unit::TestCase
|
|
575
658
|
assert user.posts.include?(post)
|
576
659
|
user.remove_post(post)
|
577
660
|
assert !user.posts.any?{|p| post.id == p.id}
|
578
|
-
assert_equal [], user.instance_variable_get("@posts")
|
661
|
+
assert_equal [], user.instance_variable_get("@posts")[:all]
|
579
662
|
end
|
580
663
|
|
581
664
|
should "save the removed item with the nullified foreign key" do
|
@@ -636,7 +719,7 @@ class CouchTest < Test::Unit::TestCase
|
|
636
719
|
post2 = Post.create(:user => user)
|
637
720
|
user.remove_all_posts
|
638
721
|
assert_equal [], user.posts
|
639
|
-
assert_equal [], user.instance_variable_get("@posts")
|
722
|
+
assert_equal [], user.instance_variable_get("@posts")[:all]
|
640
723
|
end
|
641
724
|
|
642
725
|
context "when counting" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simply_stored
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mathias Meyer, Jonathan Weiss
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-18 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|