will_paginate_couchrest 0.2.2 → 0.3.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/README.rdoc +4 -0
- data/VERSION +1 -1
- data/lib/will_paginate_couchrest.rb +35 -10
- data/lib/will_paginate_couchrest/class_methods.rb +126 -127
- data/lib/will_paginate_couchrest/proxy_methods.rb +18 -20
- data/spec/spec_helper.rb +4 -3
- data/spec/will_paginate_couchrest_spec.rb +78 -71
- metadata +5 -5
data/README.rdoc
CHANGED
@@ -10,6 +10,10 @@ Automatically generate views with an extra reduce method used to generate the to
|
|
10
10
|
|
11
11
|
== History
|
12
12
|
|
13
|
+
2010-06-26 - 0.3.1 - Minor fix, duplicate view options to avoid ExtendedDocument bug
|
14
|
+
|
15
|
+
2010-06-21 - 0.3.0 - Added support for new CouchRest Model
|
16
|
+
|
13
17
|
2010-04-05 - 0.2.0 - Added support for CouchRest Proxy class
|
14
18
|
|
15
19
|
2010-03-05 - 0.1.0 - Initial version
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.1
|
@@ -1,22 +1,47 @@
|
|
1
1
|
|
2
|
-
require
|
3
|
-
require
|
2
|
+
require 'will_paginate'
|
3
|
+
require 'will_paginate_couchrest/class_methods'
|
4
|
+
require 'will_paginate_couchrest/proxy_methods'
|
4
5
|
|
5
6
|
# Take the liberty of adding ourself to the couchrest library
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
if defined?(CouchRest::ExtendedDocument)
|
9
|
+
module CouchRest
|
10
|
+
class ExtendedDocument < Document
|
11
|
+
include CouchRest::WillPaginate
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module CouchRest
|
16
|
+
module Mixins
|
17
|
+
module ClassProxy
|
18
|
+
class Proxy
|
19
|
+
include CouchRest::WillPaginate::ProxyMethods
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
10
23
|
end
|
11
24
|
end
|
12
25
|
|
13
|
-
|
14
|
-
module
|
15
|
-
module
|
16
|
-
class
|
17
|
-
include CouchRest::
|
26
|
+
if defined?(CouchRest::Model::Base)
|
27
|
+
module CouchRest
|
28
|
+
module Model
|
29
|
+
class Base < Document
|
30
|
+
include CouchRest::WillPaginate
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module CouchRest
|
36
|
+
module Model
|
37
|
+
module ClassProxy
|
38
|
+
class Proxy
|
39
|
+
include CouchRest::WillPaginate::ProxyMethods
|
40
|
+
end
|
18
41
|
end
|
19
42
|
end
|
20
43
|
end
|
21
44
|
end
|
22
45
|
|
46
|
+
|
47
|
+
|
@@ -1,147 +1,146 @@
|
|
1
1
|
module CouchRest
|
2
|
-
module
|
3
|
-
module WillPaginate
|
2
|
+
module WillPaginate
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
8
|
+
module ClassMethods
|
9
|
+
# Define a CouchDB will paginate view. The name of the view will be the concatenation
|
10
|
+
# of <tt>paginate_by</tt> and the keys joined by <tt>_and_</tt>
|
11
|
+
#
|
12
|
+
# ==== Example paginated views:
|
13
|
+
#
|
14
|
+
# class Post
|
15
|
+
# # view with default options
|
16
|
+
# # query with Post.paginate_by_date
|
17
|
+
# paginated_view_by :date, :descending => true
|
18
|
+
#
|
19
|
+
# # view with compound sort-keys
|
20
|
+
# # query with Post.by_user_id_and_date
|
21
|
+
# paginated_view_by :user_id, :date
|
22
|
+
#
|
23
|
+
# # view with custom map/reduce functions
|
24
|
+
# # query with Post.by_tags :reduce => true
|
25
|
+
# paginated_view_by :tags,
|
26
|
+
# :map =>
|
27
|
+
# "function(doc) {
|
28
|
+
# if (doc['couchrest-type'] == 'Post' && doc.tags) {
|
29
|
+
# doc.tags.forEach(function(tag){
|
30
|
+
# emit(doc.tag, 1);
|
31
|
+
# });
|
32
|
+
# }
|
33
|
+
# }",
|
34
|
+
# :reduce =>
|
35
|
+
# "function(keys, values, rereduce) {
|
36
|
+
# return sum(values);
|
37
|
+
# }"
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# <tt>paginated_view_by :date</tt> will create a view defined by this Javascript
|
41
|
+
# function:
|
42
|
+
#
|
43
|
+
# function(doc) {
|
44
|
+
# if (doc['couchrest-type'] == 'Post' && doc.date) {
|
45
|
+
# emit(doc.date, 1);
|
46
|
+
# }
|
47
|
+
# }
|
48
|
+
#
|
49
|
+
# And a standard summing reduce function like the following:
|
50
|
+
#
|
51
|
+
# function(keys, values, rereduce) {
|
52
|
+
# return sum(values);
|
53
|
+
# }
|
54
|
+
#
|
55
|
+
# It can be queried by calling <tt>Post.paginate_by_date</tt> which accepts all
|
56
|
+
# valid options for CouchRest::Database#view. In addition, calling with
|
57
|
+
# the <tt>:raw => true</tt> option will return the view rows
|
58
|
+
# themselves. By default <tt>Post.by_date</tt> will return the
|
59
|
+
# documents included in the generated view.
|
60
|
+
#
|
61
|
+
# For further details on <tt>view_by</tt>'s other options, please see the
|
62
|
+
# standard documentation.
|
63
|
+
def paginated_view_by(*keys)
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
# Prepare the Traditional view
|
66
|
+
opts = keys.last.is_a?(Hash) ? keys.pop : {}
|
67
|
+
view_name = "by_#{keys.join('_and_')}"
|
68
|
+
method_name = "paginate_#{view_name}"
|
70
69
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
doc_keys = keys.collect{|k| "doc['#{k}']"}
|
71
|
+
key_emit = doc_keys.length == 1 ? "#{doc_keys.first}" : "[#{doc_keys.join(', ')}]"
|
72
|
+
guards = opts.delete(:guards) || []
|
73
|
+
guards.push("(doc['couchrest-type'] == '#{self.to_s}')")
|
74
|
+
guards.concat doc_keys
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
}
|
76
|
+
opts = {
|
77
|
+
:map => "
|
78
|
+
function( doc ) {
|
79
|
+
if (#{guards.join(' && ')}) {
|
80
|
+
emit(#{key_emit}, 1 );
|
83
81
|
}
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
82
|
+
}
|
83
|
+
",
|
84
|
+
:reduce => "
|
85
|
+
function(keys, values, rereduce) {
|
86
|
+
return sum(values);
|
87
|
+
}
|
88
|
+
"
|
89
|
+
}.merge(opts)
|
91
90
|
|
92
|
-
|
93
|
-
|
91
|
+
# View prepared, send to traditional view_by
|
92
|
+
view_by keys, opts
|
94
93
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
94
|
+
instance_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
95
|
+
def #{method_name}(options = {})
|
96
|
+
paginated_view('#{view_name}', options)
|
97
|
+
end
|
98
|
+
RUBY_EVAL
|
99
|
+
end
|
101
100
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
101
|
+
##
|
102
|
+
# Generate a Will Paginate collection from all the available
|
103
|
+
# documents stored with a matching couchrest-type.
|
104
|
+
#
|
105
|
+
# Requires no declaration as the 'all' view is built into couchrest
|
106
|
+
# Extended Documents.
|
107
|
+
#
|
108
|
+
def paginate_all(options = {})
|
109
|
+
paginated_view(:all, options)
|
110
|
+
end
|
112
111
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
112
|
+
##
|
113
|
+
# Return a WillPaginate collection suitable for usage
|
114
|
+
#
|
115
|
+
def paginated_view(view_name, options = {})
|
116
|
+
raise "Missing per_page parameter" if options[:per_page].nil?
|
118
117
|
|
119
|
-
|
118
|
+
options[:page] ||= 1
|
120
119
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
129
|
-
p_options = options.merge(
|
130
|
-
:design_doc => self.to_s, :view_name => view_name,
|
131
|
-
:include_docs => true
|
132
|
-
)
|
133
|
-
# Only provide the reduce parameter when necessary. This is when the view has
|
134
|
-
# been set with a reduce method and requires the reduce boolean parameter
|
135
|
-
# to be either true or false on all requests.
|
136
|
-
p_options[:reduce] = false unless view_name.to_sym == :all
|
137
|
-
results = paginate(p_options)
|
138
|
-
pager.replace( results )
|
120
|
+
::WillPaginate::Collection.create( options[:page], options[:per_page] ) do |pager|
|
121
|
+
# perform view count first (should create designs if missing)
|
122
|
+
if view_name.to_sym == :all
|
123
|
+
pager.total_entries = count({:database => options[:database]})
|
124
|
+
else
|
125
|
+
total = view( view_name, options.update(:reduce => true).dup )['rows'].pop
|
126
|
+
pager.total_entries = total ? total['value'] : 0
|
139
127
|
end
|
128
|
+
p_options = options.merge(
|
129
|
+
:design_doc => self.to_s,
|
130
|
+
:view_name => view_name,
|
131
|
+
:include_docs => true
|
132
|
+
)
|
133
|
+
# Only provide the reduce parameter when necessary. This is when the view has
|
134
|
+
# been set with a reduce method and requires the reduce boolean parameter
|
135
|
+
# to be either true or false on all requests.
|
136
|
+
p_options[:reduce] = false unless view_name.to_sym == :all
|
137
|
+
results = paginate(p_options)
|
138
|
+
pager.replace( results )
|
140
139
|
end
|
141
140
|
end
|
142
|
-
|
143
141
|
end
|
144
|
-
|
142
|
+
|
143
|
+
end
|
145
144
|
end # module CouchRest
|
146
145
|
|
147
146
|
|
@@ -1,28 +1,26 @@
|
|
1
1
|
module CouchRest
|
2
|
-
module
|
3
|
-
module
|
4
|
-
module ProxyMethods
|
2
|
+
module WillPaginate
|
3
|
+
module ProxyMethods
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def paginated_view(view_name, opts = {})
|
17
|
-
opts = {
|
18
|
-
:database => @database
|
19
|
-
}.merge(opts)
|
20
|
-
result = @klass.paginated_view(view_name, opts)
|
21
|
-
result.each{|doc| doc.database = @database if respond_to?(:database) } if result
|
22
|
-
result
|
5
|
+
def method_missing(m, *args, &block)
|
6
|
+
if m.to_s =~ /^paginate_(.+)/ && @klass.respond_to?(m)
|
7
|
+
view_name = $1 # view name
|
8
|
+
opts = args.shift || {}
|
9
|
+
paginated_view(view_name, opts)
|
10
|
+
else
|
11
|
+
super
|
23
12
|
end
|
13
|
+
end
|
24
14
|
|
15
|
+
def paginated_view(view_name, opts = {})
|
16
|
+
opts = {
|
17
|
+
:database => @database
|
18
|
+
}.merge(opts)
|
19
|
+
result = @klass.paginated_view(view_name, opts)
|
20
|
+
result.each{|doc| doc.database = @database if respond_to?(:database) } if result
|
21
|
+
result
|
25
22
|
end
|
23
|
+
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,12 +2,13 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
2
2
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
3
|
|
4
4
|
require 'rubygems'
|
5
|
-
require '
|
6
|
-
require '
|
5
|
+
require 'couchrest_extended_document'
|
6
|
+
require 'couchrest_model'
|
7
7
|
require 'will_paginate_couchrest'
|
8
8
|
require 'spec'
|
9
9
|
require 'spec/autorun'
|
10
10
|
|
11
|
+
|
11
12
|
unless defined?(SPEC_COUCH)
|
12
13
|
COUCH_URL = "http://127.0.0.1:5984"
|
13
14
|
COUCH_NAME = 'couchrest-test'
|
@@ -26,6 +27,6 @@ Spec::Runner.configure do |config|
|
|
26
27
|
}
|
27
28
|
|
28
29
|
config.after(:all) do
|
29
|
-
SPEC_COUCH.delete!
|
30
|
+
SPEC_COUCH.delete!
|
30
31
|
end
|
31
32
|
end
|
@@ -1,97 +1,104 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
describe CouchRest::
|
3
|
+
describe CouchRest::WillPaginate do
|
4
4
|
|
5
|
-
class
|
5
|
+
class SomeExtendedDoc < CouchRest::ExtendedDocument
|
6
6
|
use_database SPEC_COUCH
|
7
|
-
|
8
7
|
property :name
|
9
|
-
|
10
8
|
paginated_view_by :name
|
11
9
|
end
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
it "should call view_by method when paginated view_by included" do
|
18
|
-
SomeDoc.should_receive(:view_by)
|
19
|
-
class SomeDoc
|
20
|
-
paginated_view_by :name
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should respond to the view and paginated method" do
|
25
|
-
SomeDoc.should respond_to :paginate_by_name
|
26
|
-
# @some_doc.stub(:id).and_return(123)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should accept request when no results" do
|
30
|
-
docs = SomeDoc.paginate_by_name(:per_page => 5)
|
31
|
-
docs.total_entries.should eql(0)
|
11
|
+
class SomeModel < CouchRest::Model::Base
|
12
|
+
use_database SPEC_COUCH
|
13
|
+
property :name
|
14
|
+
paginated_view_by :name
|
32
15
|
end
|
33
16
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
docs.current_page.should eql(1)
|
38
|
-
end
|
17
|
+
[SomeExtendedDoc, SomeModel].each do |klass|
|
18
|
+
|
19
|
+
describe klass do
|
39
20
|
|
40
|
-
|
41
|
-
|
42
|
-
|
21
|
+
before(:all) do
|
22
|
+
reset_test_db!
|
23
|
+
end
|
43
24
|
|
25
|
+
it "should respond to paginated_view_by class method" do
|
26
|
+
klass.should respond_to :paginated_view_by
|
27
|
+
end
|
44
28
|
|
45
|
-
|
29
|
+
it "should call view_by method when paginated view_by included" do
|
30
|
+
klass.should_receive(:view_by)
|
31
|
+
klass.paginated_view_by :name
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should respond to the view and paginated method" do
|
35
|
+
klass.should respond_to :paginate_by_name
|
36
|
+
# @some_doc.stub(:id).and_return(123)
|
37
|
+
end
|
46
38
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
txt = "%02d" % i
|
51
|
-
SomeDoc.new(:name => "document #{txt}").save
|
39
|
+
it "should accept request when no results" do
|
40
|
+
docs = klass.paginate_by_name(:per_page => 5)
|
41
|
+
docs.total_entries.should eql(0)
|
52
42
|
end
|
53
|
-
end
|
54
43
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
docs.length.should eql(5)
|
61
|
-
docs.last.name.should eql('document 04')
|
62
|
-
end
|
44
|
+
it "should accept request without page" do
|
45
|
+
docs = nil
|
46
|
+
lambda { docs = klass.paginate_by_name(:per_page => 5) }.should_not raise_error
|
47
|
+
docs.current_page.should eql(1)
|
48
|
+
end
|
63
49
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
docs.length.should eql(5)
|
68
|
-
docs.last.name.should eql('document 09')
|
69
|
-
end
|
50
|
+
it "should throw an exception when missing per_page parameter" do
|
51
|
+
lambda { klass.paginate_by_name() }.should raise_error
|
52
|
+
end
|
70
53
|
|
71
|
-
it "should perform paginate on all entries" do
|
72
|
-
docs = SomeDoc.paginate_all(:page => 1, :per_page => 5)
|
73
|
-
docs.first.class.should eql(SomeDoc)
|
74
|
-
docs.total_pages.should eql(4)
|
75
|
-
docs.total_entries.should eql(20)
|
76
|
-
docs.length.should eql(5)
|
77
|
-
end
|
78
54
|
|
79
|
-
|
55
|
+
describe "performing pagination with lots of documents" do
|
56
|
+
|
57
|
+
before(:each) do
|
58
|
+
reset_test_db!
|
59
|
+
20.times do |i|
|
60
|
+
txt = "%02d" % i
|
61
|
+
klass.new(:name => "document #{txt}").save
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should produce a will paginate collection" do
|
66
|
+
docs = klass.paginate_by_name( :page => 1, :per_page => 5 )
|
67
|
+
docs.should be_a_kind_of(::WillPaginate::Collection)
|
68
|
+
docs.total_pages.should eql(4)
|
69
|
+
docs.first.name.should eql('document 00')
|
70
|
+
docs.length.should eql(5)
|
71
|
+
docs.last.name.should eql('document 04')
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should produce second page from paginate collection" do
|
75
|
+
docs = klass.paginate_by_name( :page => 2, :per_page => 5 )
|
76
|
+
docs.first.name.should eql('document 05')
|
77
|
+
docs.length.should eql(5)
|
78
|
+
docs.last.name.should eql('document 09')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should perform paginate on all entries" do
|
82
|
+
docs = klass.paginate_all(:page => 1, :per_page => 5)
|
83
|
+
docs.first.class.should eql(klass)
|
84
|
+
docs.total_pages.should eql(4)
|
85
|
+
docs.total_entries.should eql(20)
|
86
|
+
docs.length.should eql(5)
|
87
|
+
end
|
80
88
|
|
89
|
+
end
|
81
90
|
|
82
|
-
describe "using pagination via proxy class" do
|
83
|
-
before(:each) do
|
84
|
-
@proxy = SomeDoc.on(SPEC_COUCH)
|
85
|
-
end
|
86
91
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
describe "using pagination via proxy class" do
|
93
|
+
before(:each) do
|
94
|
+
@proxy = klass.on(SPEC_COUCH)
|
95
|
+
end
|
91
96
|
|
92
|
-
|
93
|
-
|
94
|
-
|
97
|
+
it "should allow paginate call on proxy" do
|
98
|
+
klass.should_receive(:paginated_view).with('by_name', {:key => 'foo', :database => SPEC_COUCH})
|
99
|
+
@proxy.paginate_by_name :key => 'foo'
|
100
|
+
end
|
101
|
+
end
|
95
102
|
end
|
96
103
|
end
|
97
104
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 3
|
8
|
+
- 1
|
9
|
+
version: 0.3.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- samlown
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-07-07 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -96,5 +96,5 @@ signing_key:
|
|
96
96
|
specification_version: 3
|
97
97
|
summary: adds will-paginate support to CouchRest
|
98
98
|
test_files:
|
99
|
-
- spec/will_paginate_couchrest_spec.rb
|
100
99
|
- spec/spec_helper.rb
|
100
|
+
- spec/will_paginate_couchrest_spec.rb
|