Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Getting designs view and design doc tests working properly

  • Loading branch information...
commit fa5ef9e592c3d110a86bf31bf8b86d44e2133ec9 1 parent b9f21c6
Sam Lown samlown authored
126 lib/couchrest/model/designs/design_doc.rb
View
@@ -1,126 +0,0 @@
-
-module CouchRest
- module Model
- module Designs
-
- class Design < ::CouchRest::Design
-
- # The model Class that this design belongs to
- attr_accessor :model
-
- # Can this design save itself to the database?
- # If false, the design will be loaded automatically before a view is executed.
- attr_accessor :auto_update
-
-
- # Instantiate a new design document for this model
- def initialize(model, prefix = nil)
- self.model = model
- suffix = prefix ? "_#{prefix}" : ''
- self["_id"] = "_design/#{model.to_s}#{suffix}"
- apply_defaults
- end
-
- # Create a new view object.
- # This overrides the normal CouchRest Design view method
- def view(opts = {}, name = nil)
- CouchRest::Model::Designs::View.new(self, model, opts, name)
- end
-
- def sync(db = nil)
- if auto_update
- db ||= model.database
-
- # do we need to continue?
- return self if cache_checksum(db) == checksum
-
- # Load up the last copy. We never overwrite the remote copy
- # as it may contain views that are not used or known about by
- # our model.
- doc = load_from_database(database)
- if doc
- return self if doc['couchrest-hash'] == checksum
- # Different! Update.
- doc.merge!(to_hash)
- else
- # No previous doc, use our version.
- doc = self
- end
- db.save_doc(doc)
-
- set_cache_checksum(db, checksum)
- self
- end
- end
-
- def checksum
- self['couchrest-hash'] || checksum!
- end
-
- protected
-
- def load_from_database(db = database)
- db.get(self['_id'])
- rescue RestClient::ResourceNotFound
- nil
- end
-
- # Calculate and update the checksum of the Design document.
- # Used for ensuring the latest version has been sent to the database.
- #
- # This will generate an flatterned, ordered array of all the elements of the
- # design document, convert to string then generate an MD5 Hash. This should
- # result in a consisitent Hash accross all platforms.
- #
- def checksum!
- # create a copy of basic elements
- base = self.dup
- base.delete('_id')
- base.delete('_rev')
- base.delete('couchrest-hash')
- result = nil
- flatten =
- lambda {|r|
- (recurse = lambda {|v|
- if v.is_a?(Hash) || v.is_a?(CouchRest::Document)
- v.to_a.map{|v| recurse.call(v)}.flatten
- elsif v.is_a?(Array)
- v.flatten.map{|v| recurse.call(v)}
- else
- v.to_s
- end
- }).call(r)
- }
- self['couchrest-hash'] = Digest::MD5.hexdigest(flatten.call(base).sort.join(''))
- end
-
- # Override the default #uri method for one that accepts
- # the current database.
- # This is used by the caching code.
- def uri(db)
- "#{db.root}/#{self['_id']}"
- end
-
- def cache
- Thread.current[:couchrest_design_cache] ||= {}
- end
- def cache_checksum(db)
- cache[uri(db)]
- end
- def set_cache_checksum(db, checksum)
- cache[uri(db)] = checksum
- end
-
- def apply_defaults
- merge!(
- "language" => "javascript",
- "views" => { }
- )
- end
-
- end
- end
- end
-end
-
-
2  lib/couchrest/model/designs/view.rb
View
@@ -476,7 +476,7 @@ def define(model, design_doc, name, opts = {})
end
else
# Assume there is always a map method
- opts['map'] ||= true
+ opts[:map] ||= true
end
design_doc['views'] ||= {}
2  spec/spec_helper.rb
View
@@ -28,7 +28,7 @@
cr = TEST_SERVER
test_dbs = cr.databases.select { |db| db =~ /^#{TESTDB}/ }
test_dbs.each do |db|
- #cr.database(db).delete! rescue nil
+ cr.database(db).delete! rescue nil
end
end
end
34 spec/unit/designs/design_doc.rb
View
@@ -1,34 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-
-describe CouchRest::Model::Designs::DesignDoc do
-
- before :all do
- reset_test_db!
- end
-
-
-
-
-
-
- describe "Checksum calculations" do
-
- it "should calculate a consistent checksum for model" do
- WithTemplateAndUniqueID.design_doc.checksum!.should eql('caa2b4c27abb82b4e37421de76d96ffc')
- end
-
- it "should calculate checksum for complex model" do
- Article.design_doc.checksum!.should eql('70dff8caea143bf40fad09adf0701104')
- end
-
- it "should cache the generated checksum value" do
- Article.design_doc.checksum!
- Article.design_doc['couchrest-hash'].should_not be_blank
- end
-
- end
-
-
-end
34 spec/unit/designs/design_spec.rb
View
@@ -133,6 +133,40 @@ class DesignSampleModel < CouchRest::Model::Base
end
+ describe "checksum" do
+
+ before :all do
+ @mod = DesignSampleModel
+ @doc = @mod.design_doc
+ end
+
+ it "should return fresh checksum when not calculated earlier" do
+ @doc.checksum.should_not be_blank
+ end
+
+ it "should provide same checksum without refresh on re-request" do
+ chk = @doc.checksum
+ @doc.should_not_receive(:chaecksum!)
+ @doc.checksum.should eql(chk)
+ end
+
+ it "should provide new checksum if the design has changed" do
+ chk = @doc.checksum
+ @doc['views']['all']['map'] += '// comment'
+ @doc.checksum.should_not eql(chk)
+ end
+
+ end
+
+ describe "database" do
+ it "should provide model's database" do
+ @mod = DesignSampleModel
+ @doc = @mod.design_doc
+ @mod.should_receive(:database)
+ @doc.database
+ end
+ end
+
end
102 spec/unit/designs/view_spec.rb
View
@@ -16,6 +16,7 @@ class DesignViewModel < CouchRest::Model::Base
describe "(unit tests)" do
before :each do
+ @mod = DesignViewModel
@klass = CouchRest::Model::Designs::View
end
@@ -30,14 +31,15 @@ class DesignViewModel < CouchRest::Model::Base
describe "with CouchRest Model" do
it "should setup attributes" do
- @obj = @klass.new(DesignViewModel, {}, 'test_view')
- @obj.model.should eql(DesignViewModel)
+ @obj = @klass.new(@mod.design_doc, @mod, {}, 'test_view')
+ @obj.design_doc.should eql(@mod.design_doc)
+ @obj.model.should eql(@mod)
@obj.name.should eql('test_view')
@obj.query.should be_empty
end
it "should complain if there is no name" do
- lambda { @klass.new(DesignViewModel, {}, nil) }.should raise_error
+ lambda { @klass.new(@mod.design_doc, @mod, {}, nil) }.should raise_error(/Name must be provided/)
end
end
@@ -45,12 +47,12 @@ class DesignViewModel < CouchRest::Model::Base
describe "with previous view instance" do
before :each do
- first = @klass.new(DesignViewModel, {}, 'test_view')
- @obj = @klass.new(first, {:foo => :bar})
+ first = @klass.new(@mod.design_doc, @mod, {}, 'test_view')
+ @obj = @klass.new(@mod.design_doc, first, {:foo => :bar})
end
it "should copy attributes" do
- @obj.model.should eql(DesignViewModel)
+ @obj.model.should eql(@mod)
@obj.name.should eql('test_view')
@obj.query.should eql({:foo => :bar})
end
@@ -59,42 +61,63 @@ class DesignViewModel < CouchRest::Model::Base
end
- describe ".create" do
+ describe ".define" do
- before :each do
- @design_doc = {}
- DesignViewModel.stub!(:design_doc).and_return(@design_doc)
- end
+ describe "with no auto update" do
+ before :each do
+ @design_doc = { }
+ @design_doc.stub!(:auto_update).and_return(false)
+ end
- it "should add a basic view" do
- @klass.create(DesignViewModel, 'test_view', :map => 'foo')
- @design_doc['views']['test_view'].should_not be_nil
- end
+ it "should set map view to true" do
+ @klass.define(DesignViewModel, @design_doc, 'test_view')
+ @design_doc['views']['test_view']['map'].should eql(true)
+ @design_doc['views']['test_view']['reduce'].should be_false
+ end
- it "should auto generate mapping from name" do
- lambda { @klass.create(DesignViewModel, 'by_title') }.should_not raise_error
- str = @design_doc['views']['by_title']['map']
- str.should include("((doc['#{DesignViewModel.model_type_key}'] == 'DesignViewModel') && (doc['title'] != null))")
- str.should include("emit(doc['title'], 1);")
- str = @design_doc['views']['by_title']['reduce']
- str.should include("return sum(values);")
+ it "should set reduce to true if set" do
+ @klass.define(DesignViewModel, @design_doc, 'test_view', :reduce => true)
+ @design_doc['views']['test_view']['map'].should eql(true)
+ @design_doc['views']['test_view']['reduce'].should eql(true)
+ end
end
- it "should auto generate mapping from name with and" do
- @klass.create(DesignViewModel, 'by_title_and_name')
- str = @design_doc['views']['by_title_and_name']['map']
- str.should include("(doc['title'] != null) && (doc['name'] != null)")
- str.should include("emit([doc['title'], doc['name']], 1);")
- str = @design_doc['views']['by_title_and_name']['reduce']
- str.should include("return sum(values);")
- end
+ describe "with auto update" do
+
+ before :each do
+ @design_doc = { }
+ @design_doc.stub!(:auto_update).and_return(true)
+ end
+
+ it "should add a basic view" do
+ @klass.define(DesignViewModel, @design_doc, 'test_view', :map => 'foo')
+ @design_doc['views']['test_view'].should_not be_nil
+ end
+
+ it "should auto generate mapping from name" do
+ lambda { @klass.define(DesignViewModel, @design_doc, 'by_title') }.should_not raise_error
+ str = @design_doc['views']['by_title']['map']
+ str.should include("((doc['#{DesignViewModel.model_type_key}'] == 'DesignViewModel') && (doc['title'] != null))")
+ str.should include("emit(doc['title'], 1);")
+ str = @design_doc['views']['by_title']['reduce']
+ str.should include("return sum(values);")
+ end
+ it "should auto generate mapping from name with and" do
+ @klass.define(DesignViewModel, @design_doc, 'by_title_and_name')
+ str = @design_doc['views']['by_title_and_name']['map']
+ str.should include("(doc['title'] != null) && (doc['name'] != null)")
+ str.should include("emit([doc['title'], doc['name']], 1);")
+ str = @design_doc['views']['by_title_and_name']['reduce']
+ str.should include("return sum(values);")
+ end
+ end
end
describe "instance methods" do
before :each do
- @obj = @klass.new(DesignViewModel, {}, 'test_view')
+ @obj = @klass.new(@mod.design_doc, @mod, {}, 'test_view')
end
describe "#rows" do
@@ -532,13 +555,6 @@ class DesignViewModel < CouchRest::Model::Base
end
end
- describe "#design_doc" do
- it "should call design_doc on model" do
- @obj.model.should_receive(:design_doc)
- @obj.send(:design_doc)
- end
- end
-
describe "#can_reduce?" do
it "should check and prove true" do
@obj.should_receive(:name).and_return('test_view')
@@ -557,8 +573,8 @@ class DesignViewModel < CouchRest::Model::Base
# disable real execution!
@design_doc = mock("DesignDoc")
@design_doc.stub!(:view_on)
- @obj.model.stub!(:save_design_doc)
- @obj.model.stub!(:design_doc).and_return(@design_doc)
+ @design_doc.stub!(:sync)
+ @obj.stub!(:design_doc).and_return(@design_doc)
end
it "should return previous result if set" do
@@ -582,7 +598,7 @@ class DesignViewModel < CouchRest::Model::Base
it "should call to save the design document" do
@obj.should_receive(:can_reduce?).and_return(false)
- @obj.model.should_receive(:save_design_doc).with(DB)
+ @design_doc.should_receive(:sync).with(DB)
@obj.send(:execute)
end
@@ -595,9 +611,9 @@ class DesignViewModel < CouchRest::Model::Base
it "should remove nil values from query" do
@obj.should_receive(:can_reduce?).and_return(true)
- @obj.stub!(:use_database).and_return('database')
+ @obj.stub!(:use_database).and_return(@mod.database)
@obj.query = {:reduce => true, :limit => nil, :skip => nil}
- @design_doc.should_receive(:view_on).with('database', 'test_view', {:reduce => true})
+ @design_doc.should_receive(:view_on).with(@mod.database, 'test_view', {:reduce => true})
@obj.send(:execute)
end
Please sign in to comment.
Something went wrong with that request. Please try again.