simply_stored 0.1.14 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
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[:force_reload]
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
- if forced_reload || instance_variable_get("@#{name}").nil?
21
- instance_variable_set("@#{name}", find_associated(name, self.class, :with_deleted => with_deleted))
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
- instance_variable_get("@#{name}")
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
- if forced_reload || instance_variable_get("@#{name}").nil?
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}", through_objects)
61
+ cached_results[cache_key] = through_objects
62
+ instance_variable_set("@#{name}", cached_results)
51
63
  end
52
- instance_variable_get("@#{name}")
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
- cached_version = instance_variable_get("@#{name}") || []
64
- instance_variable_set("@#{name}", cached_version << value)
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
- cached_version = instance_variable_get("@#{name}") || []
82
- instance_variable_set("@#{name}", cached_version.delete_if{|item| item.id == value.id})
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)
@@ -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", :reduce => false, :key => id))
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}", :reduce => false, :key => id))
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
- should "return all instances" do
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.14
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-13 00:00:00 +01:00
12
+ date: 2010-02-18 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency