couch_view 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/features/couch_view.conditions.feature +142 -0
- data/features/couch_view.config.feature +9 -9
- data/features/couch_view.feature +61 -1
- data/features/step_definitions/couch_view.conditions.rb +11 -0
- data/lib/couch_view/conditions.rb +37 -0
- data/lib/couch_view/config.rb +9 -9
- data/lib/couch_view.rb +1 -0
- data/readme.markdown +175 -123
- metadata +9 -4
@@ -0,0 +1,142 @@
|
|
1
|
+
Feature: CouchView::Config::Conditions
|
2
|
+
|
3
|
+
CouchView::Config::Conditions are a simple way to keep track of the conditions in a view configuration.
|
4
|
+
|
5
|
+
h2. Instantiation
|
6
|
+
|
7
|
+
To create a new CouchView::Config::Conditions instance, simply call ".new" on it.
|
8
|
+
|
9
|
+
During instantiation, you can pass some modules to it representing conditions:
|
10
|
+
|
11
|
+
conditions_config = CouchView::Config::Conditions.new Condition1, Condition2
|
12
|
+
|
13
|
+
h2. Adding conditions
|
14
|
+
|
15
|
+
You can add more conditions to it by passing them to the "add_conditions":
|
16
|
+
|
17
|
+
conditions_config.add_conditions Condition3, Condition4
|
18
|
+
|
19
|
+
If you add a condition that's namespaced, the name of the condition will be defaulted to the unqualified class name:
|
20
|
+
|
21
|
+
conditions_config.add_condition Namespace::Subspace::ConditionX
|
22
|
+
|
23
|
+
conditions_Config.conditions[:condition_x] #==> Namespace::Subspace::ConditionX
|
24
|
+
|
25
|
+
h2. Adding named conditions
|
26
|
+
|
27
|
+
You can add named conditions to your config by calling a method on them with the name you want to reference the condition by:
|
28
|
+
|
29
|
+
conditions_config.published Conditions::Published
|
30
|
+
|
31
|
+
h2. Getting all of the conditions
|
32
|
+
|
33
|
+
If you call the "conditions" method without any arguments, you'll receive a hash of all of the conditions. The key is the name of a condition, the value is the condition module.
|
34
|
+
|
35
|
+
#conditions_config.conditions
|
36
|
+
# #==> {
|
37
|
+
# :condition1 => Condition1,
|
38
|
+
# :condition2 => Condition2,
|
39
|
+
# :condition3 => Condition3,
|
40
|
+
# :condition4 => Condition4,
|
41
|
+
# :published => Conditions::Published
|
42
|
+
# }
|
43
|
+
|
44
|
+
|
45
|
+
Scenario: Conditions passed during CouchView::Config::Conditions instantiation
|
46
|
+
Given the following conditions:
|
47
|
+
"""
|
48
|
+
module Published; end
|
49
|
+
module Visible; end
|
50
|
+
"""
|
51
|
+
|
52
|
+
When I instantiate a CouchView::Config::Conditions object and pass those condition modules to it:
|
53
|
+
"""
|
54
|
+
@conditions_config = CouchView::Config::Conditions.new Published, Visible
|
55
|
+
"""
|
56
|
+
|
57
|
+
Then the "conditions" method on the config should return those conditions:
|
58
|
+
"""
|
59
|
+
@conditions_config.conditions.should == {
|
60
|
+
:published => Published,
|
61
|
+
:visible => Visible
|
62
|
+
}
|
63
|
+
"""
|
64
|
+
|
65
|
+
|
66
|
+
Scenario: Adding conditions after instantiation
|
67
|
+
Given the following conditions:
|
68
|
+
"""
|
69
|
+
module Published; end
|
70
|
+
module Visible; end
|
71
|
+
"""
|
72
|
+
|
73
|
+
And a CouchView::Config::Conditions object:
|
74
|
+
"""
|
75
|
+
@conditions_config = CouchView::Config::Conditions.new
|
76
|
+
"""
|
77
|
+
|
78
|
+
When I pass those condition modules to the condition config object's "add_conditions" method:
|
79
|
+
"""
|
80
|
+
@conditions_config.add_conditions Published, Visible
|
81
|
+
"""
|
82
|
+
|
83
|
+
Then the "conditions" method on the config should return those conditions:
|
84
|
+
"""
|
85
|
+
@conditions_config.conditions.should == {
|
86
|
+
:published => Published,
|
87
|
+
:visible => Visible
|
88
|
+
}
|
89
|
+
"""
|
90
|
+
|
91
|
+
Scenario: Creating named conditions
|
92
|
+
Given the following conditions:
|
93
|
+
"""
|
94
|
+
module Published; end
|
95
|
+
module Visible; end
|
96
|
+
"""
|
97
|
+
|
98
|
+
And a CouchView::Config::Conditions object:
|
99
|
+
"""
|
100
|
+
@conditions_config = CouchView::Config::Conditions.new
|
101
|
+
"""
|
102
|
+
|
103
|
+
When I add those conditions to my config with custom names:
|
104
|
+
"""
|
105
|
+
@conditions_config.filter_by_published Published
|
106
|
+
@conditions_config.filter_by_visible Visible
|
107
|
+
"""
|
108
|
+
|
109
|
+
Then the "conditions" method on the config should return those conditions:
|
110
|
+
"""
|
111
|
+
@conditions_config.conditions.should == {
|
112
|
+
:filter_by_published => Published,
|
113
|
+
:filter_by_visible => Visible
|
114
|
+
}
|
115
|
+
"""
|
116
|
+
|
117
|
+
Scenario: Namespaced conditions get unqualified keys
|
118
|
+
Given the following conditions:
|
119
|
+
"""
|
120
|
+
module Conditions
|
121
|
+
module Published; end
|
122
|
+
module Visible; end
|
123
|
+
end
|
124
|
+
"""
|
125
|
+
|
126
|
+
And a CouchView::Config::Conditions object:
|
127
|
+
"""
|
128
|
+
@conditions_config = CouchView::Config::Conditions.new
|
129
|
+
"""
|
130
|
+
|
131
|
+
When I pass those condition modules to the condition config object's "add_conditions" method:
|
132
|
+
"""
|
133
|
+
@conditions_config.add_conditions Conditions::Published, Conditions::Visible
|
134
|
+
"""
|
135
|
+
|
136
|
+
Then the "conditions" method on the config should return those conditions:
|
137
|
+
"""
|
138
|
+
@conditions_config.conditions.should == {
|
139
|
+
:published => Conditions::Published,
|
140
|
+
:visible => Conditions::Visible
|
141
|
+
}
|
142
|
+
"""
|
@@ -92,11 +92,11 @@ Feature: CouchView::Config
|
|
92
92
|
|
93
93
|
config = CouchView::Config.new Article
|
94
94
|
config.conditions Published
|
95
|
-
config.conditions #==>
|
95
|
+
config.conditions #==> {:published => Published}
|
96
96
|
condig.conditions Visible
|
97
|
-
config.conditions #==>
|
97
|
+
config.conditions #==> {:published => Published, :visible => Visible}
|
98
98
|
config.conditions Published
|
99
|
-
config.conditions #==>
|
99
|
+
config.conditions #==> {:published => Published, :visible => Visible}
|
100
100
|
|
101
101
|
@db
|
102
102
|
Scenario: Generating a name based on the properties passed in to map over
|
@@ -225,7 +225,7 @@ Feature: CouchView::Config
|
|
225
225
|
|
226
226
|
Then the conditions should be Published and Visible:
|
227
227
|
"""
|
228
|
-
@config.conditions.should ==
|
228
|
+
@config.conditions.should == {:published => Published, :visible => Visible}
|
229
229
|
"""
|
230
230
|
|
231
231
|
And the view names should include views for published, visible, and published/visible documents:
|
@@ -267,7 +267,7 @@ Feature: CouchView::Config
|
|
267
267
|
|
268
268
|
Then the conditions method on my config should return the conditions specified:
|
269
269
|
"""
|
270
|
-
@config.conditions.should ==
|
270
|
+
@config.conditions.should == {:published => Published, :visible => Visible}
|
271
271
|
"""
|
272
272
|
|
273
273
|
@db
|
@@ -439,11 +439,11 @@ Feature: CouchView::Config
|
|
439
439
|
Then adding the same condition multiple times will result in the condition only being added once:
|
440
440
|
"""
|
441
441
|
@config.conditions Published
|
442
|
-
@config.conditions.should ==
|
442
|
+
@config.conditions.should == {:published => Published}
|
443
443
|
@config.conditions Visible
|
444
|
-
@config.conditions.should ==
|
444
|
+
@config.conditions.should == {:published => Published, :visible => Visible}
|
445
445
|
@config.conditions Published
|
446
|
-
@config.conditions.should ==
|
446
|
+
@config.conditions.should == {:published => Published, :visible => Visible}
|
447
447
|
@config.conditions Visible
|
448
|
-
@config.conditions.should ==
|
448
|
+
@config.conditions.should == {:published => Published, :visible => Visible}
|
449
449
|
"""
|
data/features/couch_view.feature
CHANGED
@@ -92,6 +92,67 @@ Feature: CouchView
|
|
92
92
|
["published_and_visible"]
|
93
93
|
"""
|
94
94
|
|
95
|
+
|
96
|
+
@focus
|
97
|
+
Scenario: Define a map on your model with named conditions
|
98
|
+
Given the following conditions:
|
99
|
+
"""
|
100
|
+
module Conditions
|
101
|
+
module Published
|
102
|
+
def conditions
|
103
|
+
"#{super} && doc.published == true"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
module Visible
|
108
|
+
def conditions
|
109
|
+
"#{super} && doc.visible == true"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
"""
|
114
|
+
|
115
|
+
When I add them as conditions to a map over my model's label property:
|
116
|
+
"""
|
117
|
+
class Article < CouchRest::Model::Base
|
118
|
+
include CouchView
|
119
|
+
|
120
|
+
property :label
|
121
|
+
property :published, TrueClass, :default => false
|
122
|
+
property :visible, TrueClass, :default => false
|
123
|
+
|
124
|
+
map :label do
|
125
|
+
conditions do
|
126
|
+
filter_by_published Conditions::Published
|
127
|
+
filter_by_visible Conditions::Visible
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
"""
|
132
|
+
|
133
|
+
And I create visible and published documents:
|
134
|
+
"""
|
135
|
+
Article.create :label => "unpublished"
|
136
|
+
Article.create :label => "published", :published => true
|
137
|
+
Article.create :label => "visible", :visible => true
|
138
|
+
Article.create :label => "published_and_visible", :published => true, :visible => true
|
139
|
+
"""
|
140
|
+
|
141
|
+
Then I should be able to query them through my query proxy:
|
142
|
+
"""
|
143
|
+
Article.map_by_label!.collect(&:label).sort.should ==
|
144
|
+
["published", "published_and_visible", "unpublished", "visible"]
|
145
|
+
|
146
|
+
Article.map_by_label.filter_by_published.get!.collect(&:label).sort.should ==
|
147
|
+
["published", "published_and_visible"]
|
148
|
+
|
149
|
+
Article.map_by_label.filter_by_visible.get!.collect(&:label).sort.should ==
|
150
|
+
["published_and_visible", "visible"]
|
151
|
+
|
152
|
+
Article.map_by_label.filter_by_published.filter_by_visible.get!.collect(&:label).sort.should ==
|
153
|
+
["published_and_visible"]
|
154
|
+
"""
|
155
|
+
|
95
156
|
|
96
157
|
Scenario: Define a map on your model with the `map` class method
|
97
158
|
Given the following map definition:
|
@@ -354,7 +415,6 @@ Feature: CouchView
|
|
354
415
|
"""
|
355
416
|
|
356
417
|
|
357
|
-
@focus
|
358
418
|
Scenario: Chaining together multiple conditions by defining a map multiple times
|
359
419
|
|
360
420
|
Given the following model:
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Given /^a CouchView::Config::Conditions object:$/ do |string|
|
2
|
+
eval string
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I pass those condition modules to the condition config object's .*:$/ do |string|
|
6
|
+
eval string
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^I add those conditions to my config with custom names:$/ do |string|
|
10
|
+
eval string
|
11
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module CouchView
|
2
|
+
class Config
|
3
|
+
class Conditions
|
4
|
+
attr_reader :conditions
|
5
|
+
|
6
|
+
def initialize(*conditions)
|
7
|
+
@conditions = {}
|
8
|
+
add_condition_modules conditions
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_conditions(*args)
|
12
|
+
add_condition_modules args
|
13
|
+
end
|
14
|
+
|
15
|
+
alias :add_condition :add_conditions
|
16
|
+
|
17
|
+
def method_missing(condition_name, *args, &block)
|
18
|
+
super if block
|
19
|
+
super unless args.count == 1
|
20
|
+
|
21
|
+
add_condition_module condition_name, args.first
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def add_condition_modules(condition_modules)
|
26
|
+
condition_modules.each do |condition_module|
|
27
|
+
condition_name = condition_module.to_s.underscore.gsub(/^.*\/([^\/]+)$/) { $1 }
|
28
|
+
add_condition_module condition_name, condition_module
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_condition_module(condition_name, condition_module)
|
33
|
+
@conditions[condition_name.to_sym] = condition_module
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/couch_view/config.rb
CHANGED
@@ -4,7 +4,7 @@ module CouchView
|
|
4
4
|
|
5
5
|
def initialize(model_class)
|
6
6
|
@model = model_class
|
7
|
-
@conditions =
|
7
|
+
@conditions = CouchView::Config::Conditions.new
|
8
8
|
end
|
9
9
|
|
10
10
|
def map(*args, &block)
|
@@ -20,12 +20,12 @@ module CouchView
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def conditions(*args)
|
24
|
-
if args.empty?
|
25
|
-
@conditions
|
23
|
+
def conditions(*args, &block)
|
24
|
+
if args.empty? && block.nil?
|
25
|
+
@conditions.conditions
|
26
26
|
else
|
27
|
-
@conditions
|
28
|
-
@conditions.
|
27
|
+
@conditions.add_conditions *args
|
28
|
+
@conditions.instance_eval &block if block
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -57,17 +57,17 @@ module CouchView
|
|
57
57
|
|
58
58
|
private
|
59
59
|
def condition_views
|
60
|
-
all_condition_subsets = @conditions.all_combinations.reject &:empty?
|
60
|
+
all_condition_subsets = @conditions.conditions.keys.all_combinations.reject &:empty?
|
61
61
|
|
62
62
|
all_condition_subsets.reject(&:empty?).inject({}) do |result, condition_combination|
|
63
63
|
condition_combination.sort! {|a,b| a.to_s <=> b.to_s}
|
64
64
|
|
65
65
|
view_name =
|
66
66
|
"#{base_view_name}_" +
|
67
|
-
condition_combination.map {|condition| condition.to_s
|
67
|
+
condition_combination.map {|condition| condition.to_s}.join("_")
|
68
68
|
|
69
69
|
map_instance = @map_class.new @model, *@properties
|
70
|
-
condition_combination.map { |condition| map_instance.extend condition }
|
70
|
+
condition_combination.map { |condition| map_instance.extend @conditions.conditions[condition] }
|
71
71
|
|
72
72
|
result[view_name.to_sym] = {
|
73
73
|
:map => map_instance.map,
|
data/lib/couch_view.rb
CHANGED
data/readme.markdown
CHANGED
@@ -15,7 +15,7 @@ This gem integrates with the `couchrest_model` gem (version ~> 1.0.0)
|
|
15
15
|
Install it as a gem:
|
16
16
|
|
17
17
|
```sh
|
18
|
-
|
18
|
+
$ gem install couch_view
|
19
19
|
```
|
20
20
|
|
21
21
|
## Your first view
|
@@ -25,28 +25,28 @@ Let's imagine that we want to create a map on our model that includes all of the
|
|
25
25
|
We can start by simply calling the "map" method on our model, passing in the :label property:
|
26
26
|
|
27
27
|
```ruby
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
class Article < CouchRest::Model::Base
|
29
|
+
include CouchView
|
30
|
+
|
31
|
+
property :label
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
map :label
|
34
|
+
end
|
35
35
|
```
|
36
36
|
|
37
37
|
This will generate a javascript map function that looks like this:
|
38
38
|
|
39
39
|
```javascript
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
function(doc){
|
41
|
+
if (doc['couchrest-type'] == 'Article')
|
42
|
+
emit(doc.label, null)
|
43
|
+
}
|
44
44
|
```
|
45
45
|
|
46
46
|
We can query this map by using the "map_by_label!" method:
|
47
47
|
|
48
48
|
```ruby
|
49
|
-
|
49
|
+
Article.map_by_label! #==> all of the articles, in order of label
|
50
50
|
```
|
51
51
|
|
52
52
|
You can use any of the standard CouchDB query options on this view; see the section "Query Proxy" for more information.
|
@@ -54,28 +54,28 @@ You can use any of the standard CouchDB query options on this view; see the sect
|
|
54
54
|
We can also count all of the articles in the "by_label" map using the `count_by_label!` method:
|
55
55
|
|
56
56
|
```ruby
|
57
|
-
|
57
|
+
Article.count_by_label! #==> 0, assuming we haven't created any articles
|
58
58
|
```
|
59
59
|
|
60
60
|
Next, let's imagine that we'd like to create a view with a compound key: let's index all of the articles in the system by author and created_at:
|
61
61
|
|
62
62
|
```ruby
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
class Article < CouchRest::Model::Base
|
64
|
+
include CouchView
|
65
|
+
property :author
|
66
|
+
timestamps!
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
map :author, :created_at
|
69
|
+
end
|
70
70
|
```
|
71
71
|
|
72
72
|
And it's as simple as that. `CouchView` generated the following javascript map function:
|
73
73
|
|
74
74
|
```javascript
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
function(doc){
|
76
|
+
if (doc['couchrest-type'] == 'Article')
|
77
|
+
emit([doc.author, doc.created_at], null)
|
78
|
+
}
|
79
79
|
```
|
80
80
|
|
81
81
|
We can now iterate over the map using the `map_by_author_and_created_at!` method, and we can count it using the `count_by_author_and_created_at!` method.
|
@@ -87,48 +87,48 @@ But what if you need to create a more complex view? `CouchView` is your friend h
|
|
87
87
|
We'll start by creating a map class:
|
88
88
|
|
89
89
|
```ruby
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
90
|
+
class ByCommentCount
|
91
|
+
include CouchView::Map
|
92
|
+
|
93
|
+
def map
|
94
|
+
<<-JS
|
95
|
+
function(doc){
|
96
|
+
if (#{conditions})
|
97
|
+
emit(doc.comments.length, null)
|
98
|
+
}
|
99
|
+
JS
|
100
|
+
end
|
101
|
+
end
|
102
102
|
```
|
103
103
|
|
104
104
|
Notice that we call the "conditions" method inside of our map. This method is mixed into our class by the `CouchView::Map` module. You'll learn how this method allows us to decorate our views with conditions in the next section. For now, let's see what happens if we simply instantiate this class and call the "map" method on it:
|
105
105
|
|
106
106
|
```ruby
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
107
|
+
ByCommentCount.new.map #==>
|
108
|
+
"
|
109
|
+
function(doc){
|
110
|
+
emit(doc.comments.length, null)
|
111
|
+
}
|
112
|
+
"
|
113
113
|
```
|
114
114
|
|
115
115
|
Well that's not very interesting... However, what if we use this map in a model?
|
116
116
|
|
117
117
|
```ruby
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
118
|
+
class Article < CouchRest::Model::Base
|
119
|
+
include CouchView
|
120
|
+
property :comments, [String]
|
121
|
+
map ByCommentCount
|
122
|
+
end
|
123
123
|
```
|
124
124
|
|
125
125
|
Now, CouchView will generate a map function on our Article design document that will look like this:
|
126
126
|
|
127
127
|
```javascript
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
128
|
+
function(doc){
|
129
|
+
if (doc['couchrest-type'] == 'Article')
|
130
|
+
emit(doc.comments.length, null)
|
131
|
+
}
|
132
132
|
```
|
133
133
|
|
134
134
|
Similar to before, we can query this index with `map_by_comment_count!` and `count_by_comment_count!`.
|
@@ -141,6 +141,59 @@ Next, let's imagine that sometimes we'd like to constrain our Article views to p
|
|
141
141
|
To start, let's define the following condition modules:
|
142
142
|
|
143
143
|
```ruby
|
144
|
+
module WebExclusive
|
145
|
+
def conditions
|
146
|
+
"#{super} && doc.web_exclusive == true"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
module Published
|
151
|
+
def conditions
|
152
|
+
"#{super} && doc.published == true"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
We can then add them into our map definitions thusly:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
class Article < CouchRest::Model::Base
|
161
|
+
include CouchView
|
162
|
+
|
163
|
+
property :label
|
164
|
+
property :web_exclusive, TrueClass, :default => false
|
165
|
+
property :published, TrueClass, :default => false
|
166
|
+
|
167
|
+
map :label do
|
168
|
+
conditions WebExclusive, Published
|
169
|
+
end
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
Now, we can constrain our `map_by_label` query proxy to consider only web exlusive articles, published articles, or both:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
Article.map_by_label.published.get!
|
177
|
+
#==> published articles ordered by label
|
178
|
+
|
179
|
+
Article.map_by_label.web_exclusive.get!
|
180
|
+
#==> web exclusive articles ordered by label
|
181
|
+
|
182
|
+
Article.map_by_label.published.web_exclusive.get!
|
183
|
+
#==> published, web exclusive articles ordered by label
|
184
|
+
```
|
185
|
+
|
186
|
+
### Naming conditions
|
187
|
+
|
188
|
+
By default, the conditions were named after the module (i.e., "web_exclusive" for WebExclusive, "published" for Published).
|
189
|
+
|
190
|
+
In a real app, it's likely that you'll end up namespacing your condition modules, in which case, the autogenerated names for your modules won't work.
|
191
|
+
|
192
|
+
Let's go back to our article example, and imagine that we namespaced our conditions under "Article::Conditions":
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
class Article
|
196
|
+
module Conditions
|
144
197
|
module WebExclusive
|
145
198
|
def conditions
|
146
199
|
"#{super} && doc.web_exclusive == true"
|
@@ -152,38 +205,37 @@ To start, let's define the following condition modules:
|
|
152
205
|
"#{super} && doc.published == true"
|
153
206
|
end
|
154
207
|
end
|
208
|
+
end
|
209
|
+
end
|
155
210
|
```
|
156
211
|
|
157
|
-
|
212
|
+
If we added these conditions to a map, the condition names would not be qualified.
|
213
|
+
|
214
|
+
If you'd prefer that they be qualified, you'll need to tell `couch_view` what to name them:
|
158
215
|
|
159
216
|
```ruby
|
160
|
-
|
161
|
-
|
217
|
+
class Article < CouchRest::Model::Base
|
218
|
+
include CouchView
|
162
219
|
|
163
|
-
|
164
|
-
|
165
|
-
|
220
|
+
property :label
|
221
|
+
property :web_exclusive, TrueClass, :default => false
|
222
|
+
property :published, TrueClass, :default => false
|
166
223
|
|
167
|
-
|
168
|
-
|
169
|
-
|
224
|
+
map :label do
|
225
|
+
conditions do
|
226
|
+
filter_by_web_exclusive Conditions::WebExclusive
|
227
|
+
filter_by_published Conditions::Published
|
170
228
|
end
|
229
|
+
end
|
230
|
+
end
|
171
231
|
```
|
172
232
|
|
173
|
-
Now
|
233
|
+
Now you can use these conditions on your proxy:
|
174
234
|
|
175
235
|
```ruby
|
176
|
-
|
177
|
-
#==> published articles ordered by label
|
178
|
-
|
179
|
-
Article.map_by_label.web_exclusive.get!
|
180
|
-
#==> web exclusive articles ordered by label
|
181
|
-
|
182
|
-
Article.map_by_label.published.web_exclusive.get!
|
183
|
-
#==> published, web exclusive articles ordered by label
|
236
|
+
Article.map_by_label.filter_by_web_exclusive.filter_by_published.each {...}
|
184
237
|
```
|
185
238
|
|
186
|
-
|
187
239
|
## Query Proxy
|
188
240
|
|
189
241
|
CouchView includes a simple query proxy system for building your map/reduce queries.
|
@@ -191,66 +243,66 @@ CouchView includes a simple query proxy system for building your map/reduce quer
|
|
191
243
|
Given the following model:
|
192
244
|
|
193
245
|
```ruby
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
246
|
+
class Article < CouchRest::Model::Base
|
247
|
+
include CouchView
|
248
|
+
map :label
|
249
|
+
end
|
198
250
|
```
|
199
251
|
|
200
252
|
When you call `map_by_label`, you'll recieve a proxy for the query you want to run:
|
201
253
|
|
202
254
|
```ruby
|
203
|
-
|
255
|
+
proxy = Article.map_by_label
|
204
256
|
```
|
205
257
|
|
206
258
|
You can now begin modifying your proxy with the standard CouchDB query options. For example, suppose we'd like to limit our result to 10. We can call either the `limit` method, or the `limit!` method. The former will return a new proxy, and leave the original untouched. The latter will modify the proxy it was called on.
|
207
259
|
|
208
260
|
```ruby
|
209
|
-
|
210
|
-
|
261
|
+
# generate a new proxy
|
262
|
+
new_proxy = proxy.limit 10
|
211
263
|
|
212
|
-
|
213
|
-
|
264
|
+
# or update the existing property
|
265
|
+
proxy.limit!(10)
|
214
266
|
```
|
215
267
|
|
216
268
|
Here's the full list of CouchDB query parameters that `CouchView` supports:
|
217
269
|
|
218
270
|
```ruby
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
271
|
+
limit
|
272
|
+
skip
|
273
|
+
startkey
|
274
|
+
endkey
|
275
|
+
startkey_docid
|
276
|
+
endkey_docid
|
277
|
+
stale
|
278
|
+
descending
|
279
|
+
group
|
280
|
+
group_level
|
281
|
+
reduce
|
282
|
+
include_docs
|
283
|
+
update_seq
|
232
284
|
```
|
233
285
|
|
234
286
|
Your query will execute when you call `each` or `get!` on it:
|
235
287
|
|
236
288
|
```ruby
|
237
|
-
|
238
|
-
|
239
|
-
|
289
|
+
Article.map_by_label.startkey!("a").endkey!("b").each do |articles|
|
290
|
+
# do something with the articles
|
291
|
+
end
|
240
292
|
|
241
|
-
|
293
|
+
# or...
|
242
294
|
|
243
|
-
|
295
|
+
articles = Article.map_by_label.startkey!("a").endkey!("b").get!
|
244
296
|
```
|
245
297
|
|
246
298
|
You can also make your `map_by_label` and `count_by_label` return immediately by adding an `!` onto the end:
|
247
299
|
|
248
300
|
```ruby
|
249
|
-
|
250
|
-
|
301
|
+
Article.map_by_label!
|
302
|
+
#==> [Article<#848283>,...]
|
251
303
|
|
252
|
-
|
253
|
-
|
304
|
+
Article.count_by_label!
|
305
|
+
#==> 5
|
254
306
|
```
|
255
307
|
|
256
308
|
## Arbitrary Reduce
|
@@ -258,26 +310,26 @@ You can also make your `map_by_label` and `count_by_label` return immediately by
|
|
258
310
|
You can add any arbitrary reduce onto your view by using the `reduce` class method. Just make sure to group it with a map by placing them both within a `couch_view` block:
|
259
311
|
|
260
312
|
```ruby
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
313
|
+
class Article < CouchRest::Model::Base
|
314
|
+
include CouchView
|
315
|
+
|
316
|
+
property :label
|
317
|
+
|
318
|
+
couch_view do
|
319
|
+
map :label
|
320
|
+
reduce <<-JS
|
321
|
+
function(key, values){
|
322
|
+
return sum(values)
|
323
|
+
}
|
324
|
+
JS
|
325
|
+
end
|
326
|
+
end
|
275
327
|
```
|
276
328
|
|
277
329
|
And now you can call it with:
|
278
330
|
|
279
331
|
```ruby
|
280
|
-
|
332
|
+
Article.reduce_by_label.get!
|
281
333
|
```
|
282
334
|
|
283
335
|
Note that you can still call `map_by_label` as well. You can't, however, call `count_by_label`.
|
@@ -290,18 +342,18 @@ As you've seen, `CouchView` will generate names for your views based on the prop
|
|
290
342
|
You can override this default name by passing a name to the `couch_view` method:
|
291
343
|
|
292
344
|
```ruby
|
293
|
-
|
294
|
-
|
345
|
+
class Article < CouchRest::Model::Base
|
346
|
+
include CouchView
|
295
347
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
348
|
+
couch_view :over_label do
|
349
|
+
map :label
|
350
|
+
end
|
351
|
+
end
|
300
352
|
```
|
301
353
|
|
302
354
|
You can now call your view using the `map_over_label` and `count_over_label` methods:
|
303
355
|
|
304
356
|
```ruby
|
305
|
-
|
306
|
-
|
357
|
+
Article.map_over_label!
|
358
|
+
Article.count_over_label!
|
307
359
|
```
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couch_view
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.3
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matt Parker
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-08-
|
18
|
+
date: 2011-08-25 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: couchrest
|
@@ -101,6 +101,7 @@ extra_rdoc_files: []
|
|
101
101
|
|
102
102
|
files:
|
103
103
|
- lib/couch_view/array.rb
|
104
|
+
- lib/couch_view/conditions.rb
|
104
105
|
- lib/couch_view/config.rb
|
105
106
|
- lib/couch_view/couch_view.rb
|
106
107
|
- lib/couch_view/count_proxy.rb
|
@@ -111,6 +112,7 @@ files:
|
|
111
112
|
- lib/couch_view.rb
|
112
113
|
- readme.markdown
|
113
114
|
- features/couch_view.array.feature
|
115
|
+
- features/couch_view.conditions.feature
|
114
116
|
- features/couch_view.config.feature
|
115
117
|
- features/couch_view.count.proxy.feature
|
116
118
|
- features/couch_view.feature
|
@@ -119,6 +121,7 @@ files:
|
|
119
121
|
- features/setup/env.rb
|
120
122
|
- features/setup/hooks.rb
|
121
123
|
- features/step_definitions/couch_view.array.rb
|
124
|
+
- features/step_definitions/couch_view.conditions.rb
|
122
125
|
- features/step_definitions/couch_view.config.rb
|
123
126
|
- features/step_definitions/couch_view.count.proxy.rb
|
124
127
|
- features/step_definitions/couch_view.map.rb
|
@@ -159,6 +162,7 @@ specification_version: 3
|
|
159
162
|
summary: Powerful views for CouchRest::Model::Base
|
160
163
|
test_files:
|
161
164
|
- features/couch_view.array.feature
|
165
|
+
- features/couch_view.conditions.feature
|
162
166
|
- features/couch_view.config.feature
|
163
167
|
- features/couch_view.count.proxy.feature
|
164
168
|
- features/couch_view.feature
|
@@ -167,6 +171,7 @@ test_files:
|
|
167
171
|
- features/setup/env.rb
|
168
172
|
- features/setup/hooks.rb
|
169
173
|
- features/step_definitions/couch_view.array.rb
|
174
|
+
- features/step_definitions/couch_view.conditions.rb
|
170
175
|
- features/step_definitions/couch_view.config.rb
|
171
176
|
- features/step_definitions/couch_view.count.proxy.rb
|
172
177
|
- features/step_definitions/couch_view.map.rb
|