Demoting collection support, using latest couchrest, ensuring reduce always included when needed
This commit is contained in:
parent
d1baf99324
commit
9e1f4282f6
12
Gemfile.lock
12
Gemfile.lock
|
@ -3,7 +3,7 @@ PATH
|
||||||
specs:
|
specs:
|
||||||
couchrest_model (1.1.0.beta)
|
couchrest_model (1.1.0.beta)
|
||||||
activemodel (~> 3.0.0)
|
activemodel (~> 3.0.0)
|
||||||
couchrest (~> 1.0.1)
|
couchrest (~> 1.0.2)
|
||||||
mime-types (~> 1.15)
|
mime-types (~> 1.15)
|
||||||
railties (~> 3.0.0)
|
railties (~> 3.0.0)
|
||||||
tzinfo (~> 0.3.22)
|
tzinfo (~> 0.3.22)
|
||||||
|
@ -28,10 +28,10 @@ GEM
|
||||||
i18n (~> 0.4)
|
i18n (~> 0.4)
|
||||||
activesupport (3.0.4)
|
activesupport (3.0.4)
|
||||||
builder (2.1.2)
|
builder (2.1.2)
|
||||||
couchrest (1.0.1)
|
couchrest (1.0.2)
|
||||||
json (>= 1.4.6)
|
json (~> 1.5.1)
|
||||||
mime-types (>= 1.15)
|
mime-types (~> 1.15)
|
||||||
rest-client (>= 1.5.1)
|
rest-client (~> 1.6.1)
|
||||||
diff-lcs (1.1.2)
|
diff-lcs (1.1.2)
|
||||||
erubis (2.6.6)
|
erubis (2.6.6)
|
||||||
abstract (>= 1.0.0)
|
abstract (>= 1.0.0)
|
||||||
|
@ -67,7 +67,7 @@ PLATFORMS
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
activemodel (~> 3.0.0)
|
activemodel (~> 3.0.0)
|
||||||
couchrest (~> 1.0.1)
|
couchrest (~> 1.0.2)
|
||||||
couchrest_model!
|
couchrest_model!
|
||||||
mime-types (~> 1.15)
|
mime-types (~> 1.15)
|
||||||
rack-test (>= 0.5.7)
|
rack-test (>= 0.5.7)
|
||||||
|
|
|
@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
||||||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||||
s.require_paths = ["lib"]
|
s.require_paths = ["lib"]
|
||||||
|
|
||||||
s.add_dependency(%q<couchrest>, "~> 1.0.1")
|
s.add_dependency(%q<couchrest>, "~> 1.0.2")
|
||||||
s.add_dependency(%q<mime-types>, "~> 1.15")
|
s.add_dependency(%q<mime-types>, "~> 1.15")
|
||||||
s.add_dependency(%q<activemodel>, "~> 3.0.0")
|
s.add_dependency(%q<activemodel>, "~> 3.0.0")
|
||||||
s.add_dependency(%q<tzinfo>, "~> 0.3.22")
|
s.add_dependency(%q<tzinfo>, "~> 0.3.22")
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
|
|
||||||
* Minor enhancements:
|
* Minor enhancements:
|
||||||
* A yield parameter in an anonymous casted model property block is no longer required (@samlown)
|
* A yield parameter in an anonymous casted model property block is no longer required (@samlown)
|
||||||
* Narrow the rescued exception to avoid catching class evaluation errors that has nothing to to with the association (thanks Simone Carletti)
|
* Narrow the rescued exception to avoid catching class evaluation errors that has nothing to to with the association (thanks Simone Carletti)
|
||||||
* Fix validate uniqueness test that was never executed (thanks Simone Carletti)
|
* Fix validate uniqueness test that was never executed (thanks Simone Carletti)
|
||||||
* Adds a #reload method to reload document attributes (thanks Simone Carletti)
|
* Adds a #reload method to reload document attributes (thanks Simone Carletti)
|
||||||
|
* CollectionProxy no longer provided by default with simple views (pending deprication)
|
||||||
|
|
||||||
== CouchRest Model 1.0.0
|
== CouchRest Model 1.0.0
|
||||||
|
|
||||||
|
|
|
@ -85,9 +85,14 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns stored defaults if there is a view named this in the design doc
|
# returns stored defaults if there is a view named this in the design doc
|
||||||
def has_view?(view)
|
def has_view?(name)
|
||||||
view = view.to_s
|
design_doc && design_doc.has_view?(name)
|
||||||
design_doc && design_doc['views'] && design_doc['views'][view]
|
end
|
||||||
|
|
||||||
|
# Check if the view can be reduced by checking to see if it has a
|
||||||
|
# reduce function.
|
||||||
|
def can_reduce_view?(name)
|
||||||
|
design_doc && design_doc.can_reduce_view?(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Dispatches to any named view.
|
# Dispatches to any named view.
|
||||||
|
@ -127,12 +132,9 @@ module CouchRest
|
||||||
if raw || (opts.has_key?(:include_docs) && opts[:include_docs] == false)
|
if raw || (opts.has_key?(:include_docs) && opts[:include_docs] == false)
|
||||||
fetch_view(db, name, opts, &block)
|
fetch_view(db, name, opts, &block)
|
||||||
else
|
else
|
||||||
if block.nil?
|
opts = opts.merge(:include_docs => true)
|
||||||
collection_proxy_for(design_doc, name, opts.merge({:database => db, :include_docs => true}))
|
view = fetch_view db, name, opts, &block
|
||||||
else
|
view['rows'].collect{|r| build_from_database(r['doc'])} if view['rows']
|
||||||
view = fetch_view db, name, opts.merge({:include_docs => true}), &block
|
|
||||||
view['rows'].collect{|r|build_from_database(r['doc'])} if view['rows']
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
89
spec/couchrest/collection_spec.rb
Normal file
89
spec/couchrest/collection_spec.rb
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
require File.expand_path("../../spec_helper", __FILE__)
|
||||||
|
require File.join(FIXTURE_PATH, 'more', 'article')
|
||||||
|
|
||||||
|
describe "Collections" do
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
reset_test_db!
|
||||||
|
Article.refresh_design_doc
|
||||||
|
titles = ["very uniq one", "really interesting", "some fun",
|
||||||
|
"really awesome", "crazy bob", "this rocks", "super rad"]
|
||||||
|
titles.each_with_index do |title,i|
|
||||||
|
a = Article.new(:title => title, :date => Date.today)
|
||||||
|
a.save
|
||||||
|
end
|
||||||
|
|
||||||
|
titles = ["yesterday very uniq one", "yesterday really interesting", "yesterday some fun",
|
||||||
|
"yesterday really awesome", "yesterday crazy bob", "yesterday this rocks"]
|
||||||
|
titles.each_with_index do |title,i|
|
||||||
|
a = Article.new(:title => title, :date => Date.today - 1)
|
||||||
|
a.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
it "should return a proxy that looks like an array of 7 Article objects" do
|
||||||
|
articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,
|
||||||
|
:key => Date.today, :include_docs => true)
|
||||||
|
articles.class.should == Array
|
||||||
|
articles.size.should == 7
|
||||||
|
end
|
||||||
|
it "should provide a class method for paginate" do
|
||||||
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
||||||
|
:per_page => 3, :descending => true, :key => Date.today, :include_docs => true)
|
||||||
|
articles.size.should == 3
|
||||||
|
|
||||||
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
||||||
|
:per_page => 3, :page => 2, :descending => true, :key => Date.today, :include_docs => true)
|
||||||
|
articles.size.should == 3
|
||||||
|
|
||||||
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
||||||
|
:per_page => 3, :page => 3, :descending => true, :key => Date.today, :include_docs => true)
|
||||||
|
articles.size.should == 1
|
||||||
|
end
|
||||||
|
it "should provide a class method for paginated_each" do
|
||||||
|
options = { :design_doc => 'Article', :view_name => 'by_date',
|
||||||
|
:per_page => 3, :page => 1, :descending => true, :key => Date.today,
|
||||||
|
:include_docs => true }
|
||||||
|
Article.paginated_each(options) do |a|
|
||||||
|
a.should_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
it "should provide a class method to get a collection for a view" do
|
||||||
|
articles = Article.find_all_article_details(:key => Date.today)
|
||||||
|
articles.class.should == Array
|
||||||
|
articles.size.should == 7
|
||||||
|
end
|
||||||
|
it "should get a subset of articles using paginate" do
|
||||||
|
articles = Article.collection_proxy_for('Article', 'by_date', :key => Date.today, :include_docs => true)
|
||||||
|
articles.paginate(:page => 1, :per_page => 3).size.should == 3
|
||||||
|
articles.paginate(:page => 2, :per_page => 3).size.should == 3
|
||||||
|
articles.paginate(:page => 3, :per_page => 3).size.should == 1
|
||||||
|
end
|
||||||
|
it "should get all articles, a few at a time, using paginated each" do
|
||||||
|
articles = Article.collection_proxy_for('Article', 'by_date', :key => Date.today, :include_docs => true)
|
||||||
|
articles.paginated_each(:per_page => 3) do |a|
|
||||||
|
a.should_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should raise an exception if design_doc is not provided" do
|
||||||
|
lambda{Article.collection_proxy_for(nil, 'by_date')}.should raise_error
|
||||||
|
lambda{Article.paginate(:view_name => 'by_date')}.should raise_error
|
||||||
|
end
|
||||||
|
it "should raise an exception if view_name is not provided" do
|
||||||
|
lambda{Article.collection_proxy_for('Article', nil)}.should raise_error
|
||||||
|
lambda{Article.paginate(:design_doc => 'Article')}.should raise_error
|
||||||
|
end
|
||||||
|
it "should be able to span multiple keys" do
|
||||||
|
articles = Article.collection_proxy_for('Article', 'by_date', :startkey => Date.today - 1, :endkey => Date.today, :include_docs => true)
|
||||||
|
articles.paginate(:page => 1, :per_page => 3).size.should == 3
|
||||||
|
articles.paginate(:page => 3, :per_page => 3).size.should == 3
|
||||||
|
articles.paginate(:page => 5, :per_page => 3).size.should == 1
|
||||||
|
end
|
||||||
|
it "should pass database parameter to pager" do
|
||||||
|
proxy = mock(:proxy)
|
||||||
|
proxy.stub!(:paginate)
|
||||||
|
::CouchRest::Model::Collection::CollectionProxy.should_receive(:new).with('database', anything(), anything(), anything(), anything()).and_return(proxy)
|
||||||
|
Article.paginate(:design_doc => 'Article', :view_name => 'by_date', :database => 'database')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -27,6 +27,20 @@ describe "Model views" do
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#has_view?" do
|
||||||
|
it "should check the design doc" do
|
||||||
|
Article.design_doc.should_receive(:has_view?).with(:test).and_return(true)
|
||||||
|
Article.has_view?(:test).should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#can_reduce_view?" do
|
||||||
|
it "should check if view has a reduce method" do
|
||||||
|
Article.design_doc.should_receive(:can_reduce_view?).with(:test).and_return(true)
|
||||||
|
Article.can_reduce_view?(:test).should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "a model with simple views and a default param" do
|
describe "a model with simple views and a default param" do
|
||||||
|
@ -184,6 +198,11 @@ describe "Model views" do
|
||||||
course.title.should eql('bbb')
|
course.title.should eql('bbb')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should perform a search for first when reduce method present" do
|
||||||
|
course = Course.first_from_view('by_active')
|
||||||
|
course.should_not be_nil
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "a ducktype view" do
|
describe "a ducktype view" do
|
||||||
|
@ -374,96 +393,5 @@ describe "Model views" do
|
||||||
Article.design_doc["views"].keys.should include("by_updated_at")
|
Article.design_doc["views"].keys.should include("by_updated_at")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "with a collection" do
|
|
||||||
before(:all) do
|
|
||||||
reset_test_db!
|
|
||||||
titles = ["very uniq one", "really interesting", "some fun",
|
|
||||||
"really awesome", "crazy bob", "this rocks", "super rad"]
|
|
||||||
titles.each_with_index do |title,i|
|
|
||||||
a = Article.new(:title => title, :date => Date.today)
|
|
||||||
a.save
|
|
||||||
end
|
|
||||||
|
|
||||||
titles = ["yesterday very uniq one", "yesterday really interesting", "yesterday some fun",
|
|
||||||
"yesterday really awesome", "yesterday crazy bob", "yesterday this rocks"]
|
|
||||||
titles.each_with_index do |title,i|
|
|
||||||
a = Article.new(:title => title, :date => Date.today - 1)
|
|
||||||
a.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
require 'date'
|
|
||||||
it "should return a proxy that looks like an array of 7 Article objects" do
|
|
||||||
articles = Article.by_date :key => Date.today
|
|
||||||
articles.class.should == Array
|
|
||||||
articles.size.should == 7
|
|
||||||
end
|
|
||||||
it "should get a subset of articles using paginate" do
|
|
||||||
articles = Article.by_date :key => Date.today
|
|
||||||
articles.paginate(:page => 1, :per_page => 3).size.should == 3
|
|
||||||
articles.paginate(:page => 2, :per_page => 3).size.should == 3
|
|
||||||
articles.paginate(:page => 3, :per_page => 3).size.should == 1
|
|
||||||
end
|
|
||||||
it "should get all articles, a few at a time, using paginated each" do
|
|
||||||
articles = Article.by_date :key => Date.today
|
|
||||||
articles.paginated_each(:per_page => 3) do |a|
|
|
||||||
a.should_not be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
it "should provide a class method to access the collection directly" do
|
|
||||||
articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,
|
|
||||||
:key => Date.today, :include_docs => true)
|
|
||||||
articles.class.should == Array
|
|
||||||
articles.size.should == 7
|
|
||||||
end
|
|
||||||
it "should provide a class method for paginate" do
|
|
||||||
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
|
||||||
:per_page => 3, :descending => true, :key => Date.today, :include_docs => true)
|
|
||||||
articles.size.should == 3
|
|
||||||
|
|
||||||
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
|
||||||
:per_page => 3, :page => 2, :descending => true, :key => Date.today, :include_docs => true)
|
|
||||||
articles.size.should == 3
|
|
||||||
|
|
||||||
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
|
||||||
:per_page => 3, :page => 3, :descending => true, :key => Date.today, :include_docs => true)
|
|
||||||
articles.size.should == 1
|
|
||||||
end
|
|
||||||
it "should provide a class method for paginated_each" do
|
|
||||||
options = { :design_doc => 'Article', :view_name => 'by_date',
|
|
||||||
:per_page => 3, :page => 1, :descending => true, :key => Date.today,
|
|
||||||
:include_docs => true }
|
|
||||||
Article.paginated_each(options) do |a|
|
|
||||||
a.should_not be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
it "should provide a class method to get a collection for a view" do
|
|
||||||
articles = Article.find_all_article_details(:key => Date.today)
|
|
||||||
articles.class.should == Array
|
|
||||||
articles.size.should == 7
|
|
||||||
end
|
|
||||||
it "should raise an exception if design_doc is not provided" do
|
|
||||||
lambda{Article.collection_proxy_for(nil, 'by_date')}.should raise_error
|
|
||||||
lambda{Article.paginate(:view_name => 'by_date')}.should raise_error
|
|
||||||
end
|
|
||||||
it "should raise an exception if view_name is not provided" do
|
|
||||||
lambda{Article.collection_proxy_for('Article', nil)}.should raise_error
|
|
||||||
lambda{Article.paginate(:design_doc => 'Article')}.should raise_error
|
|
||||||
end
|
|
||||||
it "should be able to span multiple keys" do
|
|
||||||
articles = Article.by_date :startkey => Date.today, :endkey => Date.today - 1
|
|
||||||
articles.paginate(:page => 1, :per_page => 3).size.should == 3
|
|
||||||
articles.paginate(:page => 2, :per_page => 3).size.should == 3
|
|
||||||
articles.paginate(:page => 3, :per_page => 3).size.should == 3
|
|
||||||
articles.paginate(:page => 4, :per_page => 3).size.should == 3
|
|
||||||
articles.paginate(:page => 5, :per_page => 3).size.should == 1
|
|
||||||
end
|
|
||||||
it "should pass database parameter to pager" do
|
|
||||||
proxy = mock(:proxy)
|
|
||||||
proxy.stub!(:paginate)
|
|
||||||
::CouchRest::Model::Collection::CollectionProxy.should_receive(:new).with('database', anything(), anything(), anything(), anything()).and_return(proxy)
|
|
||||||
Article.paginate(:design_doc => 'Article', :view_name => 'by_date', :database => 'database')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
2
spec/fixtures/more/article.rb
vendored
2
spec/fixtures/more/article.rb
vendored
|
@ -18,7 +18,7 @@ class Article < CouchRest::Model::Base
|
||||||
:reduce =>
|
:reduce =>
|
||||||
"function(keys, values, rereduce) {
|
"function(keys, values, rereduce) {
|
||||||
return sum(values);
|
return sum(values);
|
||||||
}"
|
}"
|
||||||
|
|
||||||
property :date, Date
|
property :date, Date
|
||||||
property :slug, :read_only => true
|
property :slug, :read_only => true
|
||||||
|
|
6
spec/fixtures/more/course.rb
vendored
6
spec/fixtures/more/course.rb
vendored
|
@ -13,13 +13,15 @@ class Course < CouchRest::Model::Base
|
||||||
property :hours, Integer
|
property :hours, Integer
|
||||||
property :profit, BigDecimal
|
property :profit, BigDecimal
|
||||||
property :started_on, :type => Date
|
property :started_on, :type => Date
|
||||||
property :updated_at, :type => DateTime
|
property :updated_at, DateTime
|
||||||
property :active, :type => TrueClass
|
property :active, :type => TrueClass
|
||||||
property :very_active, :type => TrueClass
|
property :very_active, :type => TrueClass
|
||||||
property :klass, :type => Class
|
property :klass, :type => Class
|
||||||
|
|
||||||
view_by :title
|
view_by :title
|
||||||
view_by :title, :active
|
view_by :title, :active
|
||||||
view_by :dept, :ducktype => true
|
view_by :dept, :ducktype => true
|
||||||
|
|
||||||
|
view_by :active, :map => "function(d) { if (d['#{model_type_key}'] == 'Course' && d['active']) { emit(d['updated_at'], 1); }}", :reduce => "function(k,v,r) { return sum(v); }"
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue