couch_potato 1.2.0 → 1.3.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGES.md +6 -0
- data/README.md +1 -1
- data/lib/couch_potato/persistence.rb +3 -3
- data/lib/couch_potato/rspec/matchers/map_reduce_to_matcher.rb +43 -6
- data/lib/couch_potato/rspec/matchers/map_to_matcher.rb +4 -3
- data/lib/couch_potato/version.rb +1 -1
- data/lib/couch_potato/view/view_query.rb +12 -2
- data/spec/unit/attributes_spec.rb +9 -3
- data/spec/unit/rspec_matchers_spec.rb +50 -2
- data/spec/unit/view_query_spec.rb +36 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f37912f0e7ed48878e92e5ad8ef34d106359f15
|
4
|
+
data.tar.gz: 020faa774590847e21f942504cf9fb02df3683e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a6fce1ef1c76b01c073ac3706d894d5c567d05afe20ef4177672950f96db1011c9f6aee607852a7d0c605e303250ecec4ad0acbbc9494b30b603a25690924cd
|
7
|
+
data.tar.gz: 240d66a1fcb88a3214c946fd51e924abf314410c8b14a203423626d6d777633ee0764ebffbfb2e62b707539c218da0b01da29068f717fe2057b69f1f6d9a2921
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
## Changes
|
2
2
|
|
3
|
+
### 1.3.0
|
4
|
+
|
5
|
+
* Add support for built-in couchdb reduce functions in map reduce specs (Andy Morris)
|
6
|
+
* Make specs handle CommonJS modules via module.exports as well as exports (Andy Morris)
|
7
|
+
* Changed #attributes to return a HashWithIndifferentAccess (Owen Davies)
|
8
|
+
|
3
9
|
### 1.2.0
|
4
10
|
|
5
11
|
* adds optional deep dirty tracking (andymorris)
|
data/README.md
CHANGED
@@ -360,7 +360,7 @@ You can also pass in custom map/reduce functions with the custom view spec:
|
|
360
360
|
commonJS modules can also be used in custom views:
|
361
361
|
|
362
362
|
class User
|
363
|
-
view :all, :map => "function(doc) { emit(null, require("lib/test").test)}", :lib => {:test => "exports.test = 'test'"}, :include_docs => true, :type => :custom
|
363
|
+
view :all, :map => "function(doc) { emit(null, require("views/lib/test").test)}", :lib => {:test => "exports.test = 'test'"}, :include_docs => true, :type => :custom
|
364
364
|
end
|
365
365
|
|
366
366
|
If you don't want the results to be converted into models the raw view is your friend:
|
@@ -75,7 +75,7 @@ module CouchPotato
|
|
75
75
|
# property :year
|
76
76
|
# end
|
77
77
|
# book = Book.new
|
78
|
-
# book.attributes = {
|
78
|
+
# book.attributes = {'title' => 'Time to Relax', 'year' => 2009}
|
79
79
|
# book.title # => 'Time to Relax'
|
80
80
|
# book.year # => 2009
|
81
81
|
def attributes=(hash)
|
@@ -93,9 +93,9 @@ module CouchPotato
|
|
93
93
|
# property :year
|
94
94
|
# end
|
95
95
|
# book = Book.new :year => 2009
|
96
|
-
# book.attributes # => {
|
96
|
+
# book.attributes # => {'title' => nil, 'year' => 2009}
|
97
97
|
def attributes
|
98
|
-
self.class.properties.inject(
|
98
|
+
self.class.properties.inject(ActiveSupport::HashWithIndifferentAccess.new) do |res, property|
|
99
99
|
property.value(res, self)
|
100
100
|
res
|
101
101
|
end
|
@@ -28,6 +28,45 @@ module CouchPotato
|
|
28
28
|
|
29
29
|
def matches?(view_spec)
|
30
30
|
js = <<-JS
|
31
|
+
var sum = function(values) {
|
32
|
+
return values.reduce(function(memo, value) { return memo + value; });
|
33
|
+
};
|
34
|
+
// Equivalents of couchdb built-in reduce functions whose names can be
|
35
|
+
// given as the reduce function in the view_spec:
|
36
|
+
var _sum = function(keys, values, rereduce) {
|
37
|
+
return sum(values);
|
38
|
+
}
|
39
|
+
var _count = function(keys, values, rereduce) {
|
40
|
+
if (rereduce) {
|
41
|
+
return sum(values);
|
42
|
+
} else {
|
43
|
+
return values.length;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
var _stats = function(keys, values, rereduce) {
|
47
|
+
var result = {sum: 0, count: 0, min: Number.MAX_VALUE, max: Number.MIN_VALUE, sumsqr: 0};
|
48
|
+
if (rereduce) {
|
49
|
+
for (var i in values) {
|
50
|
+
var value = values[i];
|
51
|
+
result.sum += value.sum;
|
52
|
+
result.count += value.count;
|
53
|
+
result.min = Math.min(result.min, value.min);
|
54
|
+
result.max = Math.max(result.max, value.max);
|
55
|
+
result.sumsqr += value.sumsqr;
|
56
|
+
}
|
57
|
+
} else {
|
58
|
+
for (var i in values) {
|
59
|
+
var value = values[i];
|
60
|
+
result.sum += value;
|
61
|
+
result.count += 1;
|
62
|
+
result.min = Math.min(result.min, value);
|
63
|
+
result.max = Math.max(result.max, value);
|
64
|
+
result.sumsqr += Math.pow(value, 2);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
return result;
|
68
|
+
}
|
69
|
+
|
31
70
|
var docs = #{@input_ruby.to_json};
|
32
71
|
var options = #{@options.to_json};
|
33
72
|
var map = #{view_spec.map_function};
|
@@ -36,23 +75,21 @@ module CouchPotato
|
|
36
75
|
|
37
76
|
// Map the input docs
|
38
77
|
var require = function(modulePath) {
|
39
|
-
var
|
78
|
+
var module = {exports: {}};
|
79
|
+
var exports = module.exports;
|
40
80
|
var pathArray = modulePath.split("/").slice(2);
|
41
81
|
var result = lib;
|
42
82
|
for (var i in pathArray) {
|
43
|
-
result = result[pathArray[i]]
|
83
|
+
result = result[pathArray[i]];
|
44
84
|
}
|
45
85
|
eval(result);
|
46
|
-
return exports;
|
86
|
+
return module.exports;
|
47
87
|
}
|
48
88
|
|
49
89
|
var mapResults = [];
|
50
90
|
var emit = function(key, value) {
|
51
91
|
mapResults.push({key: key, value: value});
|
52
92
|
};
|
53
|
-
var sum = function(values) {
|
54
|
-
return values.reduce(function(memo, value) { return memo + value; });
|
55
|
-
};
|
56
93
|
for (var i in docs) {
|
57
94
|
map(docs[i]);
|
58
95
|
}
|
@@ -28,14 +28,15 @@ module CouchPotato
|
|
28
28
|
var lib = #{view_spec.respond_to?(:lib) && view_spec.lib.to_json};
|
29
29
|
var result = [];
|
30
30
|
var require = function(modulePath) {
|
31
|
-
var
|
31
|
+
var module = {exports: {}};
|
32
|
+
var exports = module.exports;
|
32
33
|
var pathArray = modulePath.split("/").slice(2);
|
33
34
|
var result = lib;
|
34
35
|
for (var i in pathArray) {
|
35
|
-
result = result[pathArray[i]]
|
36
|
+
result = result[pathArray[i]];
|
36
37
|
}
|
37
38
|
eval(result);
|
38
|
-
return exports;
|
39
|
+
return module.exports;
|
39
40
|
}
|
40
41
|
|
41
42
|
var emit = function(key, value) {
|
data/lib/couch_potato/version.rb
CHANGED
@@ -26,6 +26,17 @@ module CouchPotato
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
# mainly useful for testing where you drop the database between tests.
|
30
|
+
# only after clearing the cache design docs will be updated/re-created.
|
31
|
+
def self.clear_cache
|
32
|
+
__updated_views.clear
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.__updated_views
|
36
|
+
@updated_views ||= {}
|
37
|
+
@updated_views
|
38
|
+
end
|
39
|
+
|
29
40
|
private
|
30
41
|
|
31
42
|
def update_view
|
@@ -66,8 +77,7 @@ module CouchPotato
|
|
66
77
|
end
|
67
78
|
|
68
79
|
def updated_views
|
69
|
-
|
70
|
-
@@updated_views
|
80
|
+
self.class.__updated_views
|
71
81
|
end
|
72
82
|
|
73
83
|
def query_view(parameters)
|
@@ -34,15 +34,21 @@ describe "attributes" do
|
|
34
34
|
context "attributes" do
|
35
35
|
it "should return the attributes" do
|
36
36
|
plant = Plant.new(:leaf_count => 1)
|
37
|
-
plant.attributes.should == {
|
38
|
-
|
37
|
+
plant.attributes.should == {'leaf_count' => 1, 'created_at' => nil, 'updated_at' => nil,
|
38
|
+
'typed_leaf_count' => nil, 'typed_leaf_size' => nil, 'branch' => nil}
|
39
39
|
end
|
40
40
|
|
41
|
-
it "should return the attributes via []" do
|
41
|
+
it "should return the attributes via [symbol]" do
|
42
42
|
plant = Plant.new(:leaf_count => 1)
|
43
43
|
plant.attributes[:leaf_count].should eql(plant[:leaf_count])
|
44
44
|
plant.attributes[:leaf_count].should eql(1)
|
45
45
|
end
|
46
|
+
|
47
|
+
it "should return the attributes via [string]" do
|
48
|
+
plant = Plant.new(:leaf_count => 1)
|
49
|
+
plant.attributes["leaf_count"].should eql(plant[:leaf_count])
|
50
|
+
plant.attributes["leaf_count"].should eql(1)
|
51
|
+
end
|
46
52
|
end
|
47
53
|
|
48
54
|
context "has_key?" do
|
@@ -36,7 +36,7 @@ describe CouchPotato::RSpec::MapToMatcher do
|
|
36
36
|
spec.should map({}).to([nil, "2013-05-17T15:00:00.000Z"])
|
37
37
|
end
|
38
38
|
|
39
|
-
it "should work with commonJS modules" do
|
39
|
+
it "should work with commonJS modules that use 'exports'" do
|
40
40
|
spec = stub(
|
41
41
|
:map_function => "function(doc) { var test = require('views/lib/test'); emit(null, test.test); }",
|
42
42
|
:lib => {:test => "exports.test = 'test';"}
|
@@ -44,6 +44,14 @@ describe CouchPotato::RSpec::MapToMatcher do
|
|
44
44
|
spec.should map({}).to([nil, "test"])
|
45
45
|
end
|
46
46
|
|
47
|
+
it "should work with commonJS modules that use 'module.exports'" do
|
48
|
+
spec = stub(
|
49
|
+
:map_function => "function(doc) { var test = require('views/lib/test'); emit(null, test.test); }",
|
50
|
+
:lib => {:test => "module.exports.test = 'test';"}
|
51
|
+
)
|
52
|
+
spec.should map({}).to([nil, "test"])
|
53
|
+
end
|
54
|
+
|
47
55
|
describe "failing specs" do
|
48
56
|
before(:each) do
|
49
57
|
@view_spec = stub(:map_function => "function(doc) {emit(doc.name, null)}")
|
@@ -137,7 +145,7 @@ describe CouchPotato::RSpec::MapReduceToMatcher do
|
|
137
145
|
spec.should map_reduce({}).to({"key" => nil, "value" => "2013-05-17T15:00:00.000Z"})
|
138
146
|
end
|
139
147
|
|
140
|
-
it "should handle
|
148
|
+
it "should handle CommonJS requires for modules that use 'exports'" do
|
141
149
|
spec = stub(
|
142
150
|
:map_function => "function() { var test = require('views/lib/test'); emit(null, test.test); }",
|
143
151
|
:reduce_function => "function(keys, values) { return 'test' }",
|
@@ -145,6 +153,14 @@ describe CouchPotato::RSpec::MapReduceToMatcher do
|
|
145
153
|
spec.should map_reduce({}).to({"key" => nil, "value" => "test"})
|
146
154
|
end
|
147
155
|
|
156
|
+
it "should handle CommonJS requires for modules that use 'module.exports'" do
|
157
|
+
spec = stub(
|
158
|
+
:map_function => "function() { var test = require('views/lib/test'); emit(null, test.test); }",
|
159
|
+
:reduce_function => "function(keys, values) { return 'test' }",
|
160
|
+
:lib => {:test => "module.exports.test = 'test'"})
|
161
|
+
spec.should map_reduce({}).to({"key" => nil, "value" => "test"})
|
162
|
+
end
|
163
|
+
|
148
164
|
it "should handle sum function" do
|
149
165
|
spec = stub(
|
150
166
|
:map_function => "function(doc) { emit(null, doc.age); }",
|
@@ -233,6 +249,38 @@ describe CouchPotato::RSpec::MapReduceToMatcher do
|
|
233
249
|
}.should raise_error('Expected not to map/reduce to [{"key"=>nil, "value"=>8}] but did.')
|
234
250
|
end
|
235
251
|
end
|
252
|
+
|
253
|
+
describe "couchdb built-in reduce functions" do
|
254
|
+
describe "_sum" do
|
255
|
+
it "should return the sum of emitted values" do
|
256
|
+
spec = stub(:map_function => @view_spec.map_function, :reduce_function => "_sum")
|
257
|
+
spec.should map_reduce(@docs).to({"key" => nil, "value" => 36})
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe "_count" do
|
262
|
+
it "should return the count of emitted values" do
|
263
|
+
spec = stub(:map_function => @view_spec.map_function, :reduce_function => "_count")
|
264
|
+
spec.should map_reduce(@docs).to({"key" => nil, "value" => 8})
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "_stats" do
|
269
|
+
it "should return the numerical statistics of emitted values" do
|
270
|
+
spec = stub(:map_function => @view_spec.map_function, :reduce_function => "_stats")
|
271
|
+
spec.should map_reduce(@docs).to({
|
272
|
+
"key" => nil,
|
273
|
+
"value" => {
|
274
|
+
"sum" => 36,
|
275
|
+
"count" => 8,
|
276
|
+
"min" => 1,
|
277
|
+
"max" => 8,
|
278
|
+
"sumsqr" => 204
|
279
|
+
}
|
280
|
+
})
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
236
284
|
end
|
237
285
|
|
238
286
|
describe CouchPotato::RSpec::ListAsMatcher do
|
@@ -3,6 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe CouchPotato::View::ViewQuery, 'query_view!' do
|
4
4
|
before(:each) do
|
5
5
|
CouchRest.stub(:get => nil)
|
6
|
+
CouchPotato::View::ViewQuery.clear_cache
|
6
7
|
end
|
7
8
|
|
8
9
|
it "does not pass a key if conditions are empty" do
|
@@ -24,6 +25,28 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
|
|
24
25
|
CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}, nil, {'test' => "<lib_code>"}).query_view!
|
25
26
|
end
|
26
27
|
|
28
|
+
it 'only updates a view once' do
|
29
|
+
db = double :db, view: nil
|
30
|
+
db.stub(:get).and_return({'views' => {}}, {'views' => {}, x: 1}) # return something different on the second call otherwise it would never try to update the views twice
|
31
|
+
query = CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}})
|
32
|
+
|
33
|
+
db.should_receive(:save_doc).once
|
34
|
+
|
35
|
+
2.times { query.query_view! }
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'updates a view again after clearing the view cache' do
|
39
|
+
db = double :db, view: nil
|
40
|
+
db.stub(:get).and_return({'views' => {}}, {'views' => {}, x: 1}) # return something different on the second call otherwise it would never try to update the views twice
|
41
|
+
query = CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}})
|
42
|
+
|
43
|
+
db.should_receive(:save_doc).twice
|
44
|
+
|
45
|
+
query.query_view!
|
46
|
+
CouchPotato::View::ViewQuery.clear_cache
|
47
|
+
query.query_view!
|
48
|
+
end
|
49
|
+
|
27
50
|
it 'updates a view in erlang if it does not exist' do
|
28
51
|
db = mock 'db', :get => nil, :view => nil
|
29
52
|
|
@@ -49,8 +72,10 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
|
|
49
72
|
end
|
50
73
|
|
51
74
|
it "does not update a view when the lib function hasn't changed" do
|
52
|
-
db = mock 'db', :get => {'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}
|
75
|
+
db = mock 'db', :get => {'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}, 'lib' => {'test' => '<lib_code>'}}}, :view => nil
|
76
|
+
|
53
77
|
db.should_not_receive(:save_doc)
|
78
|
+
|
54
79
|
CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}, nil, {'test' => "<lib_code>"}).query_view!
|
55
80
|
end
|
56
81
|
|
@@ -67,8 +92,10 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
|
|
67
92
|
end
|
68
93
|
|
69
94
|
it "updates a view when the lib hash has changed" do
|
70
|
-
db = mock 'db', :get => {'views' => {'view4' => {'map' => '<map_code>'}}, 'lib' => {'test' => "<test_lib>"}
|
95
|
+
db = mock 'db', :get => {'views' => {'view4' => {'map' => '<map_code>'}}}, 'lib' => {'test' => "<test_lib>"}, :view => nil
|
96
|
+
|
71
97
|
db.should_receive(:save_doc)
|
98
|
+
|
72
99
|
CouchPotato::View::ViewQuery.new(db, 'design', {:view4 => {:map => '<map_code>'}}, nil, {:test => "<test_lib>"}).query_view!
|
73
100
|
end
|
74
101
|
|
@@ -76,8 +103,8 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
|
|
76
103
|
db = mock 'db', :get => {'views' => {'view5' => {'map' => '<map_code>'}, 'lib' => {'test' => "<test_lib>"}}}, :view => nil
|
77
104
|
db.should_receive(:save_doc).with({
|
78
105
|
'views' => {
|
79
|
-
|
80
|
-
|
106
|
+
'view5' => {'map' => '<map_code>'},
|
107
|
+
'lib' => {'test' => '<test_lib>', 'test1' => '<test1_lib>'}
|
81
108
|
}
|
82
109
|
})
|
83
110
|
CouchPotato::View::ViewQuery.new(db, 'design', {:view5 => {:map => '<map_code>'}}, nil, {'test1' => '<test1_lib>'}).query_view!
|
@@ -85,12 +112,14 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
|
|
85
112
|
|
86
113
|
it "overrides libs with the same name" do
|
87
114
|
db = mock 'db', :get => {'views' => {'view6' => {'map' => '<map_code>'}, 'lib' => {'test' => "<test_lib>"}}}, :view => nil
|
115
|
+
|
88
116
|
db.should_receive(:save_doc).with({
|
89
117
|
'views' => {
|
90
|
-
|
91
|
-
|
92
|
-
}
|
118
|
+
'view6' => {'map' => '<map_code>'},
|
119
|
+
'lib' => {'test' => '<test1_lib>'}
|
120
|
+
},
|
93
121
|
})
|
122
|
+
|
94
123
|
CouchPotato::View::ViewQuery.new(db, 'design', {:view6 => {:map => '<map_code>'}}, nil, {'test' => '<test1_lib>'}).query_view!
|
95
124
|
end
|
96
125
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couch_potato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Lang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|