Renaming to CouchRest Model
Refactored basic directory structure. Moved to ActiveSupport for Validations and Callbacks. Cleaned up older code, and removed support for text property types.
This commit is contained in:
parent
9f1eea8d32
commit
c280b3a29b
70 changed files with 1725 additions and 3733 deletions
|
@ -1,21 +1,21 @@
|
|||
# encoding: utf-8
|
||||
require File.expand_path('../../spec_helper', __FILE__)
|
||||
|
||||
class Client < CouchRest::ExtendedDocument
|
||||
class Client < CouchRest::Model::Base
|
||||
use_database DB
|
||||
|
||||
property :name
|
||||
property :tax_code
|
||||
end
|
||||
|
||||
class SaleEntry < CouchRest::ExtendedDocument
|
||||
class SaleEntry < CouchRest::Model::Base
|
||||
use_database DB
|
||||
|
||||
property :description
|
||||
property :price
|
||||
end
|
||||
|
||||
class SaleInvoice < CouchRest::ExtendedDocument
|
||||
class SaleInvoice < CouchRest::Model::Base
|
||||
use_database DB
|
||||
|
||||
belongs_to :client
|
||||
|
@ -64,7 +64,7 @@ describe "Assocations" do
|
|||
|
||||
it "should raise error if class name does not exist" do
|
||||
lambda {
|
||||
class TestBadAssoc < CouchRest::ExtendedDocument
|
||||
class TestBadAssoc < CouchRest::Model::Base
|
||||
belongs_to :test_bad_item
|
||||
end
|
||||
}.should raise_error
|
||||
|
@ -99,7 +99,7 @@ describe "Assocations" do
|
|||
it "should create an associated property and collection proxy" do
|
||||
@invoice.respond_to?('entry_ids')
|
||||
@invoice.respond_to?('entry_ids=')
|
||||
@invoice.entries.class.should eql(::CouchRest::CollectionProxy)
|
||||
@invoice.entries.class.should eql(::CouchRest::CollectionOfProxy)
|
||||
end
|
||||
|
||||
it "should allow replacement of objects" do
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
require File.expand_path('../../spec_helper', __FILE__)
|
||||
|
||||
describe "ExtendedDocument attachments" do
|
||||
describe "Model attachments" do
|
||||
|
||||
describe "#has_attachment?" do
|
||||
before(:each) do
|
||||
reset_test_db!
|
||||
@obj = Basic.new
|
||||
@obj.save.should == true
|
||||
@obj.save.should be_true
|
||||
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
||||
@attachment_name = 'my_attachment'
|
||||
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
||||
|
@ -35,7 +35,7 @@ describe "ExtendedDocument attachments" do
|
|||
describe "creating an attachment" do
|
||||
before(:each) do
|
||||
@obj = Basic.new
|
||||
@obj.save.should == true
|
||||
@obj.save.should be_true
|
||||
@file_ext = File.open(FIXTURE_PATH + '/attachments/test.html')
|
||||
@file_no_ext = File.open(FIXTURE_PATH + '/attachments/README')
|
||||
@attachment_name = 'my_attachment'
|
||||
|
@ -44,14 +44,14 @@ describe "ExtendedDocument attachments" do
|
|||
|
||||
it "should create an attachment from file with an extension" do
|
||||
@obj.create_attachment(:file => @file_ext, :name => @attachment_name)
|
||||
@obj.save.should == true
|
||||
@obj.save.should be_true
|
||||
reloaded_obj = Basic.get(@obj.id)
|
||||
reloaded_obj['_attachments'][@attachment_name].should_not be_nil
|
||||
end
|
||||
|
||||
it "should create an attachment from file without an extension" do
|
||||
@obj.create_attachment(:file => @file_no_ext, :name => @attachment_name)
|
||||
@obj.save.should == true
|
||||
@obj.save.should be_true
|
||||
reloaded_obj = Basic.get(@obj.id)
|
||||
reloaded_obj['_attachments'][@attachment_name].should_not be_nil
|
||||
end
|
||||
|
@ -89,7 +89,7 @@ describe "ExtendedDocument attachments" do
|
|||
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
||||
@attachment_name = 'my_attachment'
|
||||
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
||||
@obj.save.should == true
|
||||
@obj.save.should be_true
|
||||
@file.rewind
|
||||
@content_type = 'media/mp3'
|
||||
end
|
||||
|
@ -129,7 +129,7 @@ describe "ExtendedDocument attachments" do
|
|||
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
||||
@attachment_name = 'my_attachment'
|
||||
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
||||
@obj.save.should == true
|
||||
@obj.save.should be_true
|
||||
end
|
||||
|
||||
it 'should return nil if attachment does not exist' do
|
|
@ -1,150 +1,153 @@
|
|||
require File.expand_path("../../spec_helper", __FILE__)
|
||||
|
||||
describe "ExtendedDocument", "no declarations" do
|
||||
class NoProtection < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name
|
||||
property :phone
|
||||
end
|
||||
describe "Model Attributes" do
|
||||
|
||||
it "should not protect anything through new" do
|
||||
user = NoProtection.new(:name => "will", :phone => "555-5555")
|
||||
describe "no declarations" do
|
||||
class NoProtection < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name
|
||||
property :phone
|
||||
end
|
||||
|
||||
user.name.should == "will"
|
||||
user.phone.should == "555-5555"
|
||||
end
|
||||
it "should not protect anything through new" do
|
||||
user = NoProtection.new(:name => "will", :phone => "555-5555")
|
||||
|
||||
it "should not protect anything through attributes=" do
|
||||
user = NoProtection.new
|
||||
user.attributes = {:name => "will", :phone => "555-5555"}
|
||||
user.name.should == "will"
|
||||
user.phone.should == "555-5555"
|
||||
end
|
||||
|
||||
user.name.should == "will"
|
||||
user.phone.should == "555-5555"
|
||||
end
|
||||
|
||||
it "should recreate from the database properly" do
|
||||
user = NoProtection.new
|
||||
user.name = "will"
|
||||
user.phone = "555-5555"
|
||||
user.save!
|
||||
it "should not protect anything through attributes=" do
|
||||
user = NoProtection.new
|
||||
user.attributes = {:name => "will", :phone => "555-5555"}
|
||||
|
||||
user.name.should == "will"
|
||||
user.phone.should == "555-5555"
|
||||
end
|
||||
|
||||
user = NoProtection.get(user.id)
|
||||
user.name.should == "will"
|
||||
user.phone.should == "555-5555"
|
||||
end
|
||||
end
|
||||
|
||||
describe "ExtendedDocument", "accessible flag" do
|
||||
class WithAccessible < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name, :accessible => true
|
||||
property :admin, :default => false
|
||||
end
|
||||
|
||||
it "should recognize accessible properties" do
|
||||
props = WithAccessible.accessible_properties.map { |prop| prop.name}
|
||||
props.should include("name")
|
||||
props.should_not include("admin")
|
||||
end
|
||||
|
||||
it "should protect non-accessible properties set through new" do
|
||||
user = WithAccessible.new(:name => "will", :admin => true)
|
||||
|
||||
user.name.should == "will"
|
||||
user.admin.should == false
|
||||
end
|
||||
|
||||
it "should protect non-accessible properties set through attributes=" do
|
||||
user = WithAccessible.new
|
||||
user.attributes = {:name => "will", :admin => true}
|
||||
|
||||
user.name.should == "will"
|
||||
user.admin.should == false
|
||||
end
|
||||
end
|
||||
|
||||
describe "ExtendedDocument", "protected flag" do
|
||||
class WithProtected < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name
|
||||
property :admin, :default => false, :protected => true
|
||||
end
|
||||
|
||||
it "should recognize protected properties" do
|
||||
props = WithProtected.protected_properties.map { |prop| prop.name}
|
||||
props.should_not include("name")
|
||||
props.should include("admin")
|
||||
end
|
||||
|
||||
it "should protect non-accessible properties set through new" do
|
||||
user = WithProtected.new(:name => "will", :admin => true)
|
||||
|
||||
user.name.should == "will"
|
||||
user.admin.should == false
|
||||
end
|
||||
|
||||
it "should protect non-accessible properties set through attributes=" do
|
||||
user = WithProtected.new
|
||||
user.attributes = {:name => "will", :admin => true}
|
||||
|
||||
user.name.should == "will"
|
||||
user.admin.should == false
|
||||
end
|
||||
end
|
||||
|
||||
describe "ExtendedDocument", "protected flag" do
|
||||
class WithBoth < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name, :accessible => true
|
||||
property :admin, :default => false, :protected => true
|
||||
end
|
||||
|
||||
it "should raise an error when both are set" do
|
||||
lambda { WithBoth.new }.should raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe "ExtendedDocument", "from database" do
|
||||
class WithProtected < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name
|
||||
property :admin, :default => false, :protected => true
|
||||
view_by :name
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@user = WithProtected.new
|
||||
@user.name = "will"
|
||||
@user.admin = true
|
||||
@user.save!
|
||||
end
|
||||
|
||||
def verify_attrs(user)
|
||||
user.name.should == "will"
|
||||
user.admin.should == true
|
||||
end
|
||||
|
||||
it "ExtendedDocument#get should not strip protected attributes" do
|
||||
reloaded = WithProtected.get( @user.id )
|
||||
verify_attrs reloaded
|
||||
end
|
||||
|
||||
it "ExtendedDocument#get! should not strip protected attributes" do
|
||||
reloaded = WithProtected.get!( @user.id )
|
||||
verify_attrs reloaded
|
||||
end
|
||||
|
||||
it "ExtendedDocument#all should not strip protected attributes" do
|
||||
# all creates a CollectionProxy
|
||||
docs = WithProtected.all(:key => @user.id)
|
||||
docs.size.should == 1
|
||||
reloaded = docs.first
|
||||
verify_attrs reloaded
|
||||
end
|
||||
|
||||
it "views should not strip protected attributes" do
|
||||
docs = WithProtected.by_name(:startkey => "will", :endkey => "will")
|
||||
reloaded = docs.first
|
||||
verify_attrs reloaded
|
||||
it "should recreate from the database properly" do
|
||||
user = NoProtection.new
|
||||
user.name = "will"
|
||||
user.phone = "555-5555"
|
||||
user.save!
|
||||
|
||||
user = NoProtection.get(user.id)
|
||||
user.name.should == "will"
|
||||
user.phone.should == "555-5555"
|
||||
end
|
||||
end
|
||||
|
||||
describe "Model Base", "accessible flag" do
|
||||
class WithAccessible < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name, :accessible => true
|
||||
property :admin, :default => false
|
||||
end
|
||||
|
||||
it "should recognize accessible properties" do
|
||||
props = WithAccessible.accessible_properties.map { |prop| prop.name}
|
||||
props.should include("name")
|
||||
props.should_not include("admin")
|
||||
end
|
||||
|
||||
it "should protect non-accessible properties set through new" do
|
||||
user = WithAccessible.new(:name => "will", :admin => true)
|
||||
|
||||
user.name.should == "will"
|
||||
user.admin.should == false
|
||||
end
|
||||
|
||||
it "should protect non-accessible properties set through attributes=" do
|
||||
user = WithAccessible.new
|
||||
user.attributes = {:name => "will", :admin => true}
|
||||
|
||||
user.name.should == "will"
|
||||
user.admin.should == false
|
||||
end
|
||||
end
|
||||
|
||||
describe "Model Base", "protected flag" do
|
||||
class WithProtected < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name
|
||||
property :admin, :default => false, :protected => true
|
||||
end
|
||||
|
||||
it "should recognize protected properties" do
|
||||
props = WithProtected.protected_properties.map { |prop| prop.name}
|
||||
props.should_not include("name")
|
||||
props.should include("admin")
|
||||
end
|
||||
|
||||
it "should protect non-accessible properties set through new" do
|
||||
user = WithProtected.new(:name => "will", :admin => true)
|
||||
|
||||
user.name.should == "will"
|
||||
user.admin.should == false
|
||||
end
|
||||
|
||||
it "should protect non-accessible properties set through attributes=" do
|
||||
user = WithProtected.new
|
||||
user.attributes = {:name => "will", :admin => true}
|
||||
|
||||
user.name.should == "will"
|
||||
user.admin.should == false
|
||||
end
|
||||
end
|
||||
|
||||
describe "protected flag" do
|
||||
class WithBoth < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name, :accessible => true
|
||||
property :admin, :default => false, :protected => true
|
||||
end
|
||||
|
||||
it "should raise an error when both are set" do
|
||||
lambda { WithBoth.new }.should raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe "from database" do
|
||||
class WithProtected < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name
|
||||
property :admin, :default => false, :protected => true
|
||||
view_by :name
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@user = WithProtected.new
|
||||
@user.name = "will"
|
||||
@user.admin = true
|
||||
@user.save!
|
||||
end
|
||||
|
||||
def verify_attrs(user)
|
||||
user.name.should == "will"
|
||||
user.admin.should == true
|
||||
end
|
||||
|
||||
it "Base#get should not strip protected attributes" do
|
||||
reloaded = WithProtected.get( @user.id )
|
||||
verify_attrs reloaded
|
||||
end
|
||||
|
||||
it "Base#get! should not strip protected attributes" do
|
||||
reloaded = WithProtected.get!( @user.id )
|
||||
verify_attrs reloaded
|
||||
end
|
||||
|
||||
it "Base#all should not strip protected attributes" do
|
||||
# all creates a CollectionProxy
|
||||
docs = WithProtected.all(:key => @user.id)
|
||||
docs.size.should == 1
|
||||
reloaded = docs.first
|
||||
verify_attrs reloaded
|
||||
end
|
||||
|
||||
it "views should not strip protected attributes" do
|
||||
docs = WithProtected.by_name(:startkey => "will", :endkey => "will")
|
||||
reloaded = docs.first
|
||||
verify_attrs reloaded
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
403
spec/couchrest/base_spec.rb
Normal file
403
spec/couchrest/base_spec.rb
Normal file
|
@ -0,0 +1,403 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require File.expand_path("../../spec_helper", __FILE__)
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||
require File.join(FIXTURE_PATH, 'base')
|
||||
|
||||
describe "Model Base" do
|
||||
|
||||
before(:each) do
|
||||
@obj = WithDefaultValues.new
|
||||
end
|
||||
|
||||
describe "instance database connection" do
|
||||
it "should use the default database" do
|
||||
@obj.database.name.should == 'couchrest-model-test'
|
||||
end
|
||||
|
||||
it "should override the default db" do
|
||||
@obj.database = TEST_SERVER.database!('couchrest-extendedmodel-test')
|
||||
@obj.database.name.should == 'couchrest-extendedmodel-test'
|
||||
@obj.database.delete!
|
||||
end
|
||||
end
|
||||
|
||||
describe "a new model" do
|
||||
it "should be a new document" do
|
||||
@obj = Basic.new
|
||||
@obj.rev.should be_nil
|
||||
@obj.should be_new
|
||||
@obj.should be_new_document
|
||||
@obj.should be_new_record
|
||||
end
|
||||
|
||||
it "should not failed on a nil value in argument" do
|
||||
@obj = Basic.new(nil)
|
||||
@obj.should == { 'couchrest-type' => 'Basic' }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "update attributes without saving" do
|
||||
before(:each) do
|
||||
a = Article.get "big-bad-danger" rescue nil
|
||||
a.destroy if a
|
||||
@art = Article.new(:title => "big bad danger")
|
||||
@art.save
|
||||
end
|
||||
it "should work for attribute= methods" do
|
||||
@art['title'].should == "big bad danger"
|
||||
@art.update_attributes_without_saving('date' => Time.now, :title => "super danger")
|
||||
@art['title'].should == "super danger"
|
||||
end
|
||||
it "should silently ignore _id" do
|
||||
@art.update_attributes_without_saving('_id' => 'foobar')
|
||||
@art['_id'].should_not == 'foobar'
|
||||
end
|
||||
it "should silently ignore _rev" do
|
||||
@art.update_attributes_without_saving('_rev' => 'foobar')
|
||||
@art['_rev'].should_not == 'foobar'
|
||||
end
|
||||
it "should silently ignore created_at" do
|
||||
@art.update_attributes_without_saving('created_at' => 'foobar')
|
||||
@art['created_at'].should_not == 'foobar'
|
||||
end
|
||||
it "should silently ignore updated_at" do
|
||||
@art.update_attributes_without_saving('updated_at' => 'foobar')
|
||||
@art['updated_at'].should_not == 'foobar'
|
||||
end
|
||||
it "should also work using attributes= alias" do
|
||||
@art.respond_to?(:attributes=).should be_true
|
||||
@art.attributes = {'date' => Time.now, :title => "something else"}
|
||||
@art['title'].should == "something else"
|
||||
end
|
||||
|
||||
it "should not flip out if an attribute= method is missing and ignore it" do
|
||||
lambda {
|
||||
@art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
|
||||
}.should_not raise_error
|
||||
@art.slug.should == "big-bad-danger"
|
||||
end
|
||||
|
||||
#it "should not change other attributes if there is an error" do
|
||||
# lambda {
|
||||
# @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
|
||||
# }.should raise_error
|
||||
# @art['title'].should == "big bad danger"
|
||||
#end
|
||||
end
|
||||
|
||||
describe "update attributes" do
|
||||
before(:each) do
|
||||
a = Article.get "big-bad-danger" rescue nil
|
||||
a.destroy if a
|
||||
@art = Article.new(:title => "big bad danger")
|
||||
@art.save
|
||||
end
|
||||
it "should save" do
|
||||
@art['title'].should == "big bad danger"
|
||||
@art.update_attributes('date' => Time.now, :title => "super danger")
|
||||
loaded = Article.get(@art.id)
|
||||
loaded['title'].should == "super danger"
|
||||
end
|
||||
end
|
||||
|
||||
describe "with default" do
|
||||
it "should have the default value set at initalization" do
|
||||
@obj.preset.should == {:right => 10, :top_align => false}
|
||||
end
|
||||
|
||||
it "should have the default false value explicitly assigned" do
|
||||
@obj.default_false.should == false
|
||||
end
|
||||
|
||||
it "should automatically call a proc default at initialization" do
|
||||
@obj.set_by_proc.should be_an_instance_of(Time)
|
||||
@obj.set_by_proc.should == @obj.set_by_proc
|
||||
@obj.set_by_proc.should < Time.now
|
||||
end
|
||||
|
||||
it "should let you overwrite the default values" do
|
||||
obj = WithDefaultValues.new(:preset => 'test')
|
||||
obj.preset = 'test'
|
||||
end
|
||||
|
||||
it "should work with a default empty array" do
|
||||
obj = WithDefaultValues.new(:tags => ['spec'])
|
||||
obj.tags.should == ['spec']
|
||||
end
|
||||
|
||||
it "should set default value of read-only property" do
|
||||
obj = WithDefaultValues.new
|
||||
obj.read_only_with_default.should == 'generic'
|
||||
end
|
||||
end
|
||||
|
||||
describe "simplified way of setting property types" do
|
||||
it "should set defaults" do
|
||||
obj = WithSimplePropertyType.new
|
||||
obj.preset.should eql('none')
|
||||
end
|
||||
|
||||
it "should handle arrays" do
|
||||
obj = WithSimplePropertyType.new(:tags => ['spec'])
|
||||
obj.tags.should == ['spec']
|
||||
end
|
||||
end
|
||||
|
||||
describe "a doc with template values (CR::Model spec)" do
|
||||
before(:all) do
|
||||
WithTemplateAndUniqueID.all.map{|o| o.destroy(true)}
|
||||
WithTemplateAndUniqueID.database.bulk_delete
|
||||
@tmpl = WithTemplateAndUniqueID.new
|
||||
@tmpl2 = WithTemplateAndUniqueID.new(:preset => 'not_value', 'important-field' => '1')
|
||||
end
|
||||
it "should have fields set when new" do
|
||||
@tmpl.preset.should == 'value'
|
||||
end
|
||||
it "shouldn't override explicitly set values" do
|
||||
@tmpl2.preset.should == 'not_value'
|
||||
end
|
||||
it "shouldn't override existing documents" do
|
||||
@tmpl2.save
|
||||
tmpl2_reloaded = WithTemplateAndUniqueID.get(@tmpl2.id)
|
||||
@tmpl2.preset.should == 'not_value'
|
||||
tmpl2_reloaded.preset.should == 'not_value'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "finding all instances of a model" do
|
||||
before(:all) do
|
||||
WithTemplateAndUniqueID.req_design_doc_refresh
|
||||
WithTemplateAndUniqueID.all.map{|o| o.destroy(true)}
|
||||
WithTemplateAndUniqueID.database.bulk_delete
|
||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '4').save
|
||||
end
|
||||
it "should make the design doc" do
|
||||
WithTemplateAndUniqueID.all
|
||||
d = WithTemplateAndUniqueID.design_doc
|
||||
d['views']['all']['map'].should include('WithTemplateAndUniqueID')
|
||||
end
|
||||
it "should find all" do
|
||||
rs = WithTemplateAndUniqueID.all
|
||||
rs.length.should == 4
|
||||
end
|
||||
end
|
||||
|
||||
describe "counting all instances of a model" do
|
||||
before(:each) do
|
||||
@db = reset_test_db!
|
||||
WithTemplateAndUniqueID.req_design_doc_refresh
|
||||
end
|
||||
|
||||
it ".count should return 0 if there are no docuemtns" do
|
||||
WithTemplateAndUniqueID.count.should == 0
|
||||
end
|
||||
|
||||
it ".count should return the number of documents" do
|
||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
||||
|
||||
WithTemplateAndUniqueID.count.should == 3
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding the first instance of a model" do
|
||||
before(:each) do
|
||||
@db = reset_test_db!
|
||||
# WithTemplateAndUniqueID.req_design_doc_refresh # Removed by Sam Lown, design doc should be loaded automatically
|
||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '4').save
|
||||
end
|
||||
it "should make the design doc" do
|
||||
WithTemplateAndUniqueID.all
|
||||
d = WithTemplateAndUniqueID.design_doc
|
||||
d['views']['all']['map'].should include('WithTemplateAndUniqueID')
|
||||
end
|
||||
it "should find first" do
|
||||
rs = WithTemplateAndUniqueID.first
|
||||
rs['important-field'].should == "1"
|
||||
end
|
||||
it "should return nil if no instances are found" do
|
||||
WithTemplateAndUniqueID.all.each {|obj| obj.destroy }
|
||||
WithTemplateAndUniqueID.first.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "lazily refreshing the design document" do
|
||||
before(:all) do
|
||||
@db = reset_test_db!
|
||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
||||
end
|
||||
it "should not save the design doc twice" do
|
||||
WithTemplateAndUniqueID.all
|
||||
WithTemplateAndUniqueID.req_design_doc_refresh
|
||||
WithTemplateAndUniqueID.refresh_design_doc
|
||||
rev = WithTemplateAndUniqueID.design_doc['_rev']
|
||||
WithTemplateAndUniqueID.req_design_doc_refresh
|
||||
WithTemplateAndUniqueID.refresh_design_doc
|
||||
WithTemplateAndUniqueID.design_doc['_rev'].should eql(rev)
|
||||
end
|
||||
end
|
||||
|
||||
describe "getting a model with a subobject field" do
|
||||
before(:all) do
|
||||
course_doc = {
|
||||
"title" => "Metaphysics 410",
|
||||
"professor" => {
|
||||
"name" => ["Mark", "Hinchliff"]
|
||||
},
|
||||
"ends_at" => "2008/12/19 13:00:00 +0800"
|
||||
}
|
||||
r = Course.database.save_doc course_doc
|
||||
@course = Course.get r['id']
|
||||
end
|
||||
it "should load the course" do
|
||||
@course["professor"]["name"][1].should == "Hinchliff"
|
||||
end
|
||||
it "should instantiate the professor as a person" do
|
||||
@course['professor'].last_name.should == "Hinchliff"
|
||||
end
|
||||
it "should instantiate the ends_at as a Time" do
|
||||
@course['ends_at'].should == Time.parse("2008/12/19 13:00:00 +0800")
|
||||
end
|
||||
end
|
||||
|
||||
describe "timestamping" do
|
||||
before(:each) do
|
||||
oldart = Article.get "saving-this" rescue nil
|
||||
oldart.destroy if oldart
|
||||
@art = Article.new(:title => "Saving this")
|
||||
@art.save
|
||||
end
|
||||
|
||||
it "should define the updated_at and created_at getters and set the values" do
|
||||
@obj.save
|
||||
obj = WithDefaultValues.get(@obj.id)
|
||||
obj.should be_an_instance_of(WithDefaultValues)
|
||||
obj.created_at.should be_an_instance_of(Time)
|
||||
obj.updated_at.should be_an_instance_of(Time)
|
||||
obj.created_at.to_s.should == @obj.updated_at.to_s
|
||||
end
|
||||
|
||||
it "should not change created_at on update" do
|
||||
2.times do
|
||||
lambda do
|
||||
@art.save
|
||||
end.should_not change(@art, :created_at)
|
||||
end
|
||||
end
|
||||
|
||||
it "should set the time on create" do
|
||||
(Time.now - @art.created_at).should < 2
|
||||
foundart = Article.get @art.id
|
||||
foundart.created_at.should == foundart.updated_at
|
||||
end
|
||||
it "should set the time on update" do
|
||||
@art.save
|
||||
@art.created_at.should < @art.updated_at
|
||||
end
|
||||
end
|
||||
|
||||
describe "getter and setter methods" do
|
||||
it "should try to call the arg= method before setting :arg in the hash" do
|
||||
@doc = WithGetterAndSetterMethods.new(:arg => "foo")
|
||||
@doc['arg'].should be_nil
|
||||
@doc[:arg].should be_nil
|
||||
@doc.other_arg.should == "foo-foo"
|
||||
end
|
||||
end
|
||||
|
||||
describe "initialization" do
|
||||
it "should call after_initialize method if available" do
|
||||
@doc = WithAfterInitializeMethod.new
|
||||
@doc['some_value'].should eql('value')
|
||||
end
|
||||
end
|
||||
|
||||
describe "recursive validation on a model" do
|
||||
before :each do
|
||||
reset_test_db!
|
||||
@cat = Cat.new(:name => 'Sockington')
|
||||
end
|
||||
|
||||
it "should not save if a nested casted model is invalid" do
|
||||
@cat.favorite_toy = CatToy.new
|
||||
@cat.should_not be_valid
|
||||
@cat.save.should be_false
|
||||
lambda{@cat.save!}.should raise_error
|
||||
end
|
||||
|
||||
it "should save when nested casted model is valid" do
|
||||
@cat.favorite_toy = CatToy.new(:name => 'Squeaky')
|
||||
@cat.should be_valid
|
||||
@cat.save.should be_true
|
||||
lambda{@cat.save!}.should_not raise_error
|
||||
end
|
||||
|
||||
it "should not save when nested collection contains an invalid casted model" do
|
||||
@cat.toys = [CatToy.new(:name => 'Feather'), CatToy.new]
|
||||
@cat.should_not be_valid
|
||||
@cat.save.should be_false
|
||||
lambda{@cat.save!}.should raise_error
|
||||
end
|
||||
|
||||
it "should save when nested collection contains valid casted models" do
|
||||
@cat.toys = [CatToy.new(:name => 'feather'), CatToy.new(:name => 'ball-o-twine')]
|
||||
@cat.should be_valid
|
||||
@cat.save.should be_true
|
||||
lambda{@cat.save!}.should_not raise_error
|
||||
end
|
||||
|
||||
it "should not fail if the nested casted model doesn't have validation" do
|
||||
Cat.property :trainer, Person
|
||||
Cat.validates_presence_of :name
|
||||
cat = Cat.new(:name => 'Mr Bigglesworth')
|
||||
cat.trainer = Person.new
|
||||
cat.should be_valid
|
||||
cat.save.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "searching the contents of an extended document" do
|
||||
before :each do
|
||||
@db = reset_test_db!
|
||||
|
||||
names = ["Fuzzy", "Whiskers", "Mr Bigglesworth", "Sockington", "Smitty", "Sammy", "Samson", "Simon"]
|
||||
names.each { |name| Cat.create(:name => name) }
|
||||
|
||||
search_function = { 'defaults' => {'store' => 'no', 'index' => 'analyzed_no_norms'},
|
||||
'index' => "function(doc) { ret = new Document(); ret.add(doc['name'], {'field':'name'}); return ret; }" }
|
||||
@db.save_doc({'_id' => '_design/search', 'fulltext' => {'cats' => search_function}})
|
||||
end
|
||||
|
||||
it "should be able to paginate through a large set of search results" do
|
||||
if couchdb_lucene_available?
|
||||
names = []
|
||||
Cat.paginated_each(:design_doc => "search", :view_name => "cats",
|
||||
:q => 'name:S*', :search => true, :include_docs => true, :per_page => 3) do |cat|
|
||||
cat.should_not be_nil
|
||||
names << cat.name
|
||||
end
|
||||
|
||||
names.size.should == 5
|
||||
names.should include('Sockington')
|
||||
names.should include('Smitty')
|
||||
names.should include('Sammy')
|
||||
names.should include('Samson')
|
||||
names.should include('Simon')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,39 +1,33 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require File.expand_path('../../spec_helper', __FILE__)
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
require File.join(FIXTURE_PATH, 'more', 'question')
|
||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||
|
||||
|
||||
class WithCastedModelMixin < Hash
|
||||
include CouchRest::CastedModel
|
||||
include CouchRest::Model::CastedModel
|
||||
property :name
|
||||
property :no_value
|
||||
property :details, :type => 'Object', :default => {}
|
||||
property :casted_attribute, :cast_as => 'WithCastedModelMixin'
|
||||
property :details, Object, :default => {}
|
||||
property :casted_attribute, WithCastedModelMixin
|
||||
end
|
||||
|
||||
class DummyModel < CouchRest::ExtendedDocument
|
||||
class DummyModel < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
raise "Default DB not set" if TEST_SERVER.default_database.nil?
|
||||
property :casted_attribute, WithCastedModelMixin
|
||||
property :keywords, ["String"]
|
||||
property :keywords, [String]
|
||||
property :sub_models do |child|
|
||||
child.property :title
|
||||
end
|
||||
end
|
||||
|
||||
class CastedCallbackDoc < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
raise "Default DB not set" if TEST_SERVER.default_database.nil?
|
||||
property :callback_model, :cast_as => 'WithCastedCallBackModel'
|
||||
end
|
||||
class WithCastedCallBackModel < Hash
|
||||
include CouchRest::CastedModel
|
||||
include CouchRest::Validation
|
||||
include CouchRest::Model::CastedModel
|
||||
property :name
|
||||
property :run_before_validate
|
||||
property :run_after_validate
|
||||
|
@ -46,7 +40,13 @@ class WithCastedCallBackModel < Hash
|
|||
end
|
||||
end
|
||||
|
||||
describe CouchRest::CastedModel do
|
||||
class CastedCallbackDoc < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
raise "Default DB not set" if TEST_SERVER.default_database.nil?
|
||||
property :callback_model, WithCastedCallBackModel
|
||||
end
|
||||
|
||||
describe CouchRest::Model::CastedModel do
|
||||
|
||||
describe "A non hash class including CastedModel" do
|
||||
it "should fail raising and include error" do
|
||||
|
@ -227,7 +227,7 @@ describe CouchRest::CastedModel do
|
|||
@cat.toys.push(toy)
|
||||
@cat.save.should be_true
|
||||
@cat = Cat.get @cat.id
|
||||
@cat.toys.class.should == CouchRest::CastedArray
|
||||
@cat.toys.class.should == CouchRest::Model::CastedArray
|
||||
@cat.toys.first.class.should == CatToy
|
||||
@cat.toys.first.should === toy
|
||||
end
|
||||
|
@ -240,7 +240,7 @@ describe CouchRest::CastedModel do
|
|||
end
|
||||
|
||||
it "should not fail if the casted model doesn't have validation" do
|
||||
Cat.property :masters, :cast_as => ['Person'], :default => []
|
||||
Cat.property :masters, [Person], :default => []
|
||||
Cat.validates_presence_of :name
|
||||
cat = Cat.new(:name => 'kitty')
|
||||
cat.should be_valid
|
||||
|
|
|
@ -3,7 +3,7 @@ require File.join(FIXTURE_PATH, 'more', 'cat')
|
|||
require File.join(FIXTURE_PATH, 'more', 'person')
|
||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||
|
||||
class Driver < CouchRest::ExtendedDocument
|
||||
class Driver < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
# You have to add a casted_by accessor if you want to reach a casted extended doc parent
|
||||
attr_accessor :casted_by
|
||||
|
@ -11,12 +11,11 @@ class Driver < CouchRest::ExtendedDocument
|
|||
property :name
|
||||
end
|
||||
|
||||
class Car < CouchRest::ExtendedDocument
|
||||
class Car < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
|
||||
property :name
|
||||
property :driver, :cast_as => 'Driver'
|
||||
property :backseat_driver, :cast_as => Driver
|
||||
property :driver, Driver
|
||||
end
|
||||
|
||||
describe "casting an extended document" do
|
||||
|
@ -24,17 +23,14 @@ describe "casting an extended document" do
|
|||
before(:each) do
|
||||
@driver = Driver.new(:name => 'Matt')
|
||||
@car = Car.new(:name => 'Renault 306', :driver => @driver)
|
||||
@car2 = Car.new(:name => 'Renault 306', :backseat_driver => @driver.dup)
|
||||
end
|
||||
|
||||
it "should retain all properties of the casted attribute" do
|
||||
@car.driver.should == @driver
|
||||
@car2.backseat_driver.should == @driver
|
||||
end
|
||||
|
||||
it "should let the casted document know who casted it" do
|
||||
@car.driver.casted_by.should == @car
|
||||
@car2.backseat_driver.casted_by.should == @car2
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -61,7 +57,7 @@ describe "assigning a value to casted attribute after initializing an object" do
|
|||
|
||||
end
|
||||
|
||||
describe "casting an extended document from parsed JSON" do
|
||||
describe "casting a model from parsed JSON" do
|
||||
|
||||
before(:each) do
|
||||
@driver = Driver.new(:name => 'Matt')
|
|
@ -1,6 +1,6 @@
|
|||
require File.expand_path("../../spec_helper", __FILE__)
|
||||
|
||||
class UnattachedDoc < CouchRest::ExtendedDocument
|
||||
class UnattachedDoc < CouchRest::Model::Base
|
||||
# Note: no use_database here
|
||||
property :title
|
||||
property :questions
|
||||
|
|
|
@ -1,869 +0,0 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require File.expand_path("../../spec_helper", __FILE__)
|
||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
|
||||
describe "ExtendedDocument" do
|
||||
|
||||
class WithDefaultValues < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
property :preset, :type => 'Object', :default => {:right => 10, :top_align => false}
|
||||
property :set_by_proc, :default => Proc.new{Time.now}, :cast_as => 'Time'
|
||||
property :tags, :type => ['String'], :default => []
|
||||
property :read_only_with_default, :default => 'generic', :read_only => true
|
||||
property :default_false, :type => 'Boolean', :default => false
|
||||
property :name
|
||||
timestamps!
|
||||
end
|
||||
|
||||
class WithSimplePropertyType < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name, String
|
||||
property :preset, String, :default => 'none'
|
||||
property :tags, [String]
|
||||
timestamps!
|
||||
end
|
||||
|
||||
class WithCallBacks < CouchRest::ExtendedDocument
|
||||
include ::CouchRest::Validation
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name
|
||||
property :run_before_validate
|
||||
property :run_after_validate
|
||||
property :run_before_save
|
||||
property :run_after_save
|
||||
property :run_before_create
|
||||
property :run_after_create
|
||||
property :run_before_update
|
||||
property :run_after_update
|
||||
|
||||
before_validate do |object|
|
||||
object.run_before_validate = true
|
||||
end
|
||||
after_validate do |object|
|
||||
object.run_after_validate = true
|
||||
end
|
||||
before_save do |object|
|
||||
object.run_before_save = true
|
||||
end
|
||||
after_save do |object|
|
||||
object.run_after_save = true
|
||||
end
|
||||
before_create do |object|
|
||||
object.run_before_create = true
|
||||
end
|
||||
after_create do |object|
|
||||
object.run_after_create = true
|
||||
end
|
||||
before_update do |object|
|
||||
object.run_before_update = true
|
||||
end
|
||||
after_update do |object|
|
||||
object.run_after_update = true
|
||||
end
|
||||
|
||||
property :run_one
|
||||
property :run_two
|
||||
property :run_three
|
||||
|
||||
before_save :run_one_method, :run_two_method do |object|
|
||||
object.run_three = true
|
||||
end
|
||||
def run_one_method
|
||||
self.run_one = true
|
||||
end
|
||||
def run_two_method
|
||||
self.run_two = true
|
||||
end
|
||||
|
||||
attr_accessor :run_it
|
||||
property :conditional_one
|
||||
property :conditional_two
|
||||
|
||||
before_save :conditional_one_method, :conditional_two_method, :if => proc { self.run_it }
|
||||
def conditional_one_method
|
||||
self.conditional_one = true
|
||||
end
|
||||
def conditional_two_method
|
||||
self.conditional_two = true
|
||||
end
|
||||
end
|
||||
|
||||
class WithTemplateAndUniqueID < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
unique_id do |model|
|
||||
model['important-field']
|
||||
end
|
||||
property :preset, :default => 'value'
|
||||
property :has_no_default
|
||||
end
|
||||
|
||||
class WithGetterAndSetterMethods < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
|
||||
property :other_arg
|
||||
def arg
|
||||
other_arg
|
||||
end
|
||||
|
||||
def arg=(value)
|
||||
self.other_arg = "foo-#{value}"
|
||||
end
|
||||
end
|
||||
|
||||
class WithAfterInitializeMethod < CouchRest::ExtendedDocument
|
||||
use_database TEST_SERVER.default_database
|
||||
|
||||
property :some_value
|
||||
|
||||
def after_initialize
|
||||
self.some_value ||= "value"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
before(:each) do
|
||||
@obj = WithDefaultValues.new
|
||||
end
|
||||
|
||||
describe "instance database connection" do
|
||||
it "should use the default database" do
|
||||
@obj.database.name.should == 'couchrest-test'
|
||||
end
|
||||
|
||||
it "should override the default db" do
|
||||
@obj.database = TEST_SERVER.database!('couchrest-extendedmodel-test')
|
||||
@obj.database.name.should == 'couchrest-extendedmodel-test'
|
||||
@obj.database.delete!
|
||||
end
|
||||
end
|
||||
|
||||
describe "a new model" do
|
||||
it "should be a new document" do
|
||||
@obj = Basic.new
|
||||
@obj.rev.should be_nil
|
||||
@obj.should be_new
|
||||
@obj.should be_new_document
|
||||
@obj.should be_new_record
|
||||
end
|
||||
|
||||
it "should not failed on a nil value in argument" do
|
||||
@obj = Basic.new(nil)
|
||||
@obj.should == { 'couchrest-type' => 'Basic' }
|
||||
end
|
||||
end
|
||||
|
||||
describe "creating a new document" do
|
||||
it "should instantialize and save a document" do
|
||||
article = Article.create(:title => 'my test')
|
||||
article.title.should == 'my test'
|
||||
article.should_not be_new
|
||||
end
|
||||
|
||||
it "should trigger the create callbacks" do
|
||||
doc = WithCallBacks.create(:name => 'my other test')
|
||||
doc.run_before_create.should be_true
|
||||
doc.run_after_create.should be_true
|
||||
doc.run_before_save.should be_true
|
||||
doc.run_after_save.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "creating a new document from database" do
|
||||
|
||||
it "should instantialize" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem1', '_rev' => 123, 'couchrest-type' => 'Article', 'name' => 'my test'})
|
||||
doc.class.should eql(Article)
|
||||
end
|
||||
|
||||
it "should instantialize of same class if no couchrest-type included from DB" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem1', '_rev' => 123, 'name' => 'my test'})
|
||||
doc.class.should eql(Article)
|
||||
end
|
||||
|
||||
it "should instantialize document of different type" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem2', '_rev' => 123, 'couchrest-type' => 'WithCallBacks', 'name' => 'my test'})
|
||||
doc.class.should eql(WithCallBacks)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "update attributes without saving" do
|
||||
before(:each) do
|
||||
a = Article.get "big-bad-danger" rescue nil
|
||||
a.destroy if a
|
||||
@art = Article.new(:title => "big bad danger")
|
||||
@art.save
|
||||
end
|
||||
it "should work for attribute= methods" do
|
||||
@art['title'].should == "big bad danger"
|
||||
@art.update_attributes_without_saving('date' => Time.now, :title => "super danger")
|
||||
@art['title'].should == "super danger"
|
||||
end
|
||||
it "should silently ignore _id" do
|
||||
@art.update_attributes_without_saving('_id' => 'foobar')
|
||||
@art['_id'].should_not == 'foobar'
|
||||
end
|
||||
it "should silently ignore _rev" do
|
||||
@art.update_attributes_without_saving('_rev' => 'foobar')
|
||||
@art['_rev'].should_not == 'foobar'
|
||||
end
|
||||
it "should silently ignore created_at" do
|
||||
@art.update_attributes_without_saving('created_at' => 'foobar')
|
||||
@art['created_at'].should_not == 'foobar'
|
||||
end
|
||||
it "should silently ignore updated_at" do
|
||||
@art.update_attributes_without_saving('updated_at' => 'foobar')
|
||||
@art['updated_at'].should_not == 'foobar'
|
||||
end
|
||||
it "should also work using attributes= alias" do
|
||||
@art.respond_to?(:attributes=).should be_true
|
||||
@art.attributes = {'date' => Time.now, :title => "something else"}
|
||||
@art['title'].should == "something else"
|
||||
end
|
||||
|
||||
it "should not flip out if an attribute= method is missing and ignore it" do
|
||||
lambda {
|
||||
@art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
|
||||
}.should_not raise_error
|
||||
@art.slug.should == "big-bad-danger"
|
||||
end
|
||||
|
||||
#it "should not change other attributes if there is an error" do
|
||||
# lambda {
|
||||
# @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
|
||||
# }.should raise_error
|
||||
# @art['title'].should == "big bad danger"
|
||||
#end
|
||||
end
|
||||
|
||||
describe "update attributes" do
|
||||
before(:each) do
|
||||
a = Article.get "big-bad-danger" rescue nil
|
||||
a.destroy if a
|
||||
@art = Article.new(:title => "big bad danger")
|
||||
@art.save
|
||||
end
|
||||
it "should save" do
|
||||
@art['title'].should == "big bad danger"
|
||||
@art.update_attributes('date' => Time.now, :title => "super danger")
|
||||
loaded = Article.get(@art.id)
|
||||
loaded['title'].should == "super danger"
|
||||
end
|
||||
end
|
||||
|
||||
describe "with default" do
|
||||
it "should have the default value set at initalization" do
|
||||
@obj.preset.should == {:right => 10, :top_align => false}
|
||||
end
|
||||
|
||||
it "should have the default false value explicitly assigned" do
|
||||
@obj.default_false.should == false
|
||||
end
|
||||
|
||||
it "should automatically call a proc default at initialization" do
|
||||
@obj.set_by_proc.should be_an_instance_of(Time)
|
||||
@obj.set_by_proc.should == @obj.set_by_proc
|
||||
@obj.set_by_proc.should < Time.now
|
||||
end
|
||||
|
||||
it "should let you overwrite the default values" do
|
||||
obj = WithDefaultValues.new(:preset => 'test')
|
||||
obj.preset = 'test'
|
||||
end
|
||||
|
||||
it "should work with a default empty array" do
|
||||
obj = WithDefaultValues.new(:tags => ['spec'])
|
||||
obj.tags.should == ['spec']
|
||||
end
|
||||
|
||||
it "should set default value of read-only property" do
|
||||
obj = WithDefaultValues.new
|
||||
obj.read_only_with_default.should == 'generic'
|
||||
end
|
||||
end
|
||||
|
||||
describe "simplified way of setting property types" do
|
||||
it "should set defaults" do
|
||||
obj = WithSimplePropertyType.new
|
||||
obj.preset.should eql('none')
|
||||
end
|
||||
|
||||
it "should handle arrays" do
|
||||
obj = WithSimplePropertyType.new(:tags => ['spec'])
|
||||
obj.tags.should == ['spec']
|
||||
end
|
||||
end
|
||||
|
||||
describe "a doc with template values (CR::Model spec)" do
|
||||
before(:all) do
|
||||
WithTemplateAndUniqueID.all.map{|o| o.destroy(true)}
|
||||
WithTemplateAndUniqueID.database.bulk_delete
|
||||
@tmpl = WithTemplateAndUniqueID.new
|
||||
@tmpl2 = WithTemplateAndUniqueID.new(:preset => 'not_value', 'important-field' => '1')
|
||||
end
|
||||
it "should have fields set when new" do
|
||||
@tmpl.preset.should == 'value'
|
||||
end
|
||||
it "shouldn't override explicitly set values" do
|
||||
@tmpl2.preset.should == 'not_value'
|
||||
end
|
||||
it "shouldn't override existing documents" do
|
||||
@tmpl2.save
|
||||
tmpl2_reloaded = WithTemplateAndUniqueID.get(@tmpl2.id)
|
||||
@tmpl2.preset.should == 'not_value'
|
||||
tmpl2_reloaded.preset.should == 'not_value'
|
||||
end
|
||||
end
|
||||
|
||||
describe "getting a model" do
|
||||
before(:all) do
|
||||
@art = Article.new(:title => 'All About Getting')
|
||||
@art.save
|
||||
end
|
||||
it "should load and instantiate it" do
|
||||
foundart = Article.get @art.id
|
||||
foundart.title.should == "All About Getting"
|
||||
end
|
||||
it "should load and instantiate with find" do
|
||||
foundart = Article.find @art.id
|
||||
foundart.title.should == "All About Getting"
|
||||
end
|
||||
it "should return nil if `get` is used and the document doesn't exist" do
|
||||
foundart = Article.get 'matt aimonetti'
|
||||
foundart.should be_nil
|
||||
end
|
||||
it "should raise an error if `get!` is used and the document doesn't exist" do
|
||||
lambda{foundart = Article.get!('matt aimonetti')}.should raise_error
|
||||
end
|
||||
it "should raise an error if `find!` is used and the document doesn't exist" do
|
||||
lambda{foundart = Article.find!('matt aimonetti')}.should raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe "getting a model with a subobjects array" do
|
||||
before(:all) do
|
||||
course_doc = {
|
||||
"title" => "Metaphysics 200",
|
||||
"questions" => [
|
||||
{
|
||||
"q" => "Carve the ___ of reality at the ___.",
|
||||
"a" => ["beast","joints"]
|
||||
},{
|
||||
"q" => "Who layed the smack down on Leibniz's Law?",
|
||||
"a" => "Willard Van Orman Quine"
|
||||
}
|
||||
]
|
||||
}
|
||||
r = Course.database.save_doc course_doc
|
||||
@course = Course.get r['id']
|
||||
end
|
||||
it "should load the course" do
|
||||
@course.title.should == "Metaphysics 200"
|
||||
end
|
||||
it "should instantiate them as such" do
|
||||
@course["questions"][0].a[0].should == "beast"
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding all instances of a model" do
|
||||
before(:all) do
|
||||
WithTemplateAndUniqueID.req_design_doc_refresh
|
||||
WithTemplateAndUniqueID.all.map{|o| o.destroy(true)}
|
||||
WithTemplateAndUniqueID.database.bulk_delete
|
||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '4').save
|
||||
end
|
||||
it "should make the design doc" do
|
||||
WithTemplateAndUniqueID.all
|
||||
d = WithTemplateAndUniqueID.design_doc
|
||||
d['views']['all']['map'].should include('WithTemplateAndUniqueID')
|
||||
end
|
||||
it "should find all" do
|
||||
rs = WithTemplateAndUniqueID.all
|
||||
rs.length.should == 4
|
||||
end
|
||||
end
|
||||
|
||||
describe "counting all instances of a model" do
|
||||
before(:each) do
|
||||
@db = reset_test_db!
|
||||
WithTemplateAndUniqueID.req_design_doc_refresh
|
||||
end
|
||||
|
||||
it ".count should return 0 if there are no docuemtns" do
|
||||
WithTemplateAndUniqueID.count.should == 0
|
||||
end
|
||||
|
||||
it ".count should return the number of documents" do
|
||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
||||
|
||||
WithTemplateAndUniqueID.count.should == 3
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding the first instance of a model" do
|
||||
before(:each) do
|
||||
@db = reset_test_db!
|
||||
# WithTemplateAndUniqueID.req_design_doc_refresh # Removed by Sam Lown, design doc should be loaded automatically
|
||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
||||
WithTemplateAndUniqueID.new('important-field' => '4').save
|
||||
end
|
||||
it "should make the design doc" do
|
||||
WithTemplateAndUniqueID.all
|
||||
d = WithTemplateAndUniqueID.design_doc
|
||||
d['views']['all']['map'].should include('WithTemplateAndUniqueID')
|
||||
end
|
||||
it "should find first" do
|
||||
rs = WithTemplateAndUniqueID.first
|
||||
rs['important-field'].should == "1"
|
||||
end
|
||||
it "should return nil if no instances are found" do
|
||||
WithTemplateAndUniqueID.all.each {|obj| obj.destroy }
|
||||
WithTemplateAndUniqueID.first.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "lazily refreshing the design document" do
|
||||
before(:all) do
|
||||
@db = reset_test_db!
|
||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
||||
end
|
||||
it "should not save the design doc twice" do
|
||||
WithTemplateAndUniqueID.all
|
||||
WithTemplateAndUniqueID.req_design_doc_refresh
|
||||
WithTemplateAndUniqueID.refresh_design_doc
|
||||
rev = WithTemplateAndUniqueID.design_doc['_rev']
|
||||
WithTemplateAndUniqueID.req_design_doc_refresh
|
||||
WithTemplateAndUniqueID.refresh_design_doc
|
||||
WithTemplateAndUniqueID.design_doc['_rev'].should eql(rev)
|
||||
end
|
||||
end
|
||||
|
||||
describe "getting a model with a subobject field" do
|
||||
before(:all) do
|
||||
course_doc = {
|
||||
"title" => "Metaphysics 410",
|
||||
"professor" => {
|
||||
"name" => ["Mark", "Hinchliff"]
|
||||
},
|
||||
"ends_at" => "2008/12/19 13:00:00 +0800"
|
||||
}
|
||||
r = Course.database.save_doc course_doc
|
||||
@course = Course.get r['id']
|
||||
end
|
||||
it "should load the course" do
|
||||
@course["professor"]["name"][1].should == "Hinchliff"
|
||||
end
|
||||
it "should instantiate the professor as a person" do
|
||||
@course['professor'].last_name.should == "Hinchliff"
|
||||
end
|
||||
it "should instantiate the ends_at as a Time" do
|
||||
@course['ends_at'].should == Time.parse("2008/12/19 13:00:00 +0800")
|
||||
end
|
||||
end
|
||||
|
||||
describe "timestamping" do
|
||||
before(:each) do
|
||||
oldart = Article.get "saving-this" rescue nil
|
||||
oldart.destroy if oldart
|
||||
@art = Article.new(:title => "Saving this")
|
||||
@art.save
|
||||
end
|
||||
|
||||
it "should define the updated_at and created_at getters and set the values" do
|
||||
@obj.save
|
||||
obj = WithDefaultValues.get(@obj.id)
|
||||
obj.should be_an_instance_of(WithDefaultValues)
|
||||
obj.created_at.should be_an_instance_of(Time)
|
||||
obj.updated_at.should be_an_instance_of(Time)
|
||||
obj.created_at.to_s.should == @obj.updated_at.to_s
|
||||
end
|
||||
|
||||
it "should not change created_at on update" do
|
||||
2.times do
|
||||
lambda do
|
||||
@art.save
|
||||
end.should_not change(@art, :created_at)
|
||||
end
|
||||
end
|
||||
|
||||
it "should set the time on create" do
|
||||
(Time.now - @art.created_at).should < 2
|
||||
foundart = Article.get @art.id
|
||||
foundart.created_at.should == foundart.updated_at
|
||||
end
|
||||
it "should set the time on update" do
|
||||
@art.save
|
||||
@art.created_at.should < @art.updated_at
|
||||
end
|
||||
end
|
||||
|
||||
describe "basic saving and retrieving" do
|
||||
it "should work fine" do
|
||||
@obj.name = "should be easily saved and retrieved"
|
||||
@obj.save
|
||||
saved_obj = WithDefaultValues.get(@obj.id)
|
||||
saved_obj.should_not be_nil
|
||||
end
|
||||
|
||||
it "should parse the Time attributes automatically" do
|
||||
@obj.name = "should parse the Time attributes automatically"
|
||||
@obj.set_by_proc.should be_an_instance_of(Time)
|
||||
@obj.save
|
||||
@obj.set_by_proc.should be_an_instance_of(Time)
|
||||
saved_obj = WithDefaultValues.get(@obj.id)
|
||||
saved_obj.set_by_proc.should be_an_instance_of(Time)
|
||||
end
|
||||
end
|
||||
|
||||
describe "saving a model" do
|
||||
before(:all) do
|
||||
@sobj = Basic.new
|
||||
@sobj.save.should == true
|
||||
end
|
||||
|
||||
it "should save the doc" do
|
||||
doc = Basic.get(@sobj.id)
|
||||
doc['_id'].should == @sobj.id
|
||||
end
|
||||
|
||||
it "should be set for resaving" do
|
||||
rev = @obj.rev
|
||||
@sobj['another-key'] = "some value"
|
||||
@sobj.save
|
||||
@sobj.rev.should_not == rev
|
||||
end
|
||||
|
||||
it "should set the id" do
|
||||
@sobj.id.should be_an_instance_of(String)
|
||||
end
|
||||
|
||||
it "should set the type" do
|
||||
@sobj['couchrest-type'].should == 'Basic'
|
||||
end
|
||||
|
||||
describe "save!" do
|
||||
|
||||
before(:each) do
|
||||
@sobj = Card.new(:first_name => "Marcos", :last_name => "Tapajós")
|
||||
end
|
||||
|
||||
it "should return true if save the document" do
|
||||
@sobj.save!.should == true
|
||||
end
|
||||
|
||||
it "should raise error if don't save the document" do
|
||||
@sobj.first_name = nil
|
||||
lambda { @sobj.save!.should == true }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
describe "saving a model with a unique_id configured" do
|
||||
before(:each) do
|
||||
@art = Article.new
|
||||
@old = Article.database.get('this-is-the-title') rescue nil
|
||||
Article.database.delete_doc(@old) if @old
|
||||
end
|
||||
|
||||
it "should be a new document" do
|
||||
@art.should be_new
|
||||
@art.title.should be_nil
|
||||
end
|
||||
|
||||
it "should require the title" do
|
||||
lambda{@art.save}.should raise_error
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should == true
|
||||
end
|
||||
|
||||
it "should not change the slug on update" do
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should == true
|
||||
@art.title = 'new title'
|
||||
@art.save.should == true
|
||||
@art.slug.should == 'this-is-the-title'
|
||||
end
|
||||
|
||||
it "should raise an error when the slug is taken" do
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should == true
|
||||
@art2 = Article.new(:title => 'This is the title!')
|
||||
lambda{@art2.save}.should raise_error
|
||||
end
|
||||
|
||||
it "should set the slug" do
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should == true
|
||||
@art.slug.should == 'this-is-the-title'
|
||||
end
|
||||
|
||||
it "should set the id" do
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should == true
|
||||
@art.id.should == 'this-is-the-title'
|
||||
end
|
||||
end
|
||||
|
||||
describe "saving a model with a unique_id lambda" do
|
||||
before(:each) do
|
||||
@templated = WithTemplateAndUniqueID.new
|
||||
@old = WithTemplateAndUniqueID.get('very-important') rescue nil
|
||||
@old.destroy if @old
|
||||
end
|
||||
|
||||
it "should require the field" do
|
||||
lambda{@templated.save}.should raise_error
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should == true
|
||||
end
|
||||
|
||||
it "should save with the id" do
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should == true
|
||||
t = WithTemplateAndUniqueID.get('very-important')
|
||||
t.should == @templated
|
||||
end
|
||||
|
||||
it "should not change the id on update" do
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should == true
|
||||
@templated['important-field'] = 'not-important'
|
||||
@templated.save.should == true
|
||||
t = WithTemplateAndUniqueID.get('very-important')
|
||||
t.should == @templated
|
||||
end
|
||||
|
||||
it "should raise an error when the id is taken" do
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should == true
|
||||
lambda{WithTemplateAndUniqueID.new('important-field' => 'very-important').save}.should raise_error
|
||||
end
|
||||
|
||||
it "should set the id" do
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should == true
|
||||
@templated.id.should == 'very-important'
|
||||
end
|
||||
end
|
||||
|
||||
describe "destroying an instance" do
|
||||
before(:each) do
|
||||
@dobj = Basic.new
|
||||
@dobj.save.should == true
|
||||
end
|
||||
it "should return true" do
|
||||
result = @dobj.destroy
|
||||
result.should == true
|
||||
end
|
||||
it "should be resavable" do
|
||||
@dobj.destroy
|
||||
@dobj.rev.should be_nil
|
||||
@dobj.id.should be_nil
|
||||
@dobj.save.should == true
|
||||
end
|
||||
it "should make it go away" do
|
||||
@dobj.destroy
|
||||
lambda{Basic.get!(@dobj.id)}.should raise_error
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "callbacks" do
|
||||
|
||||
before(:each) do
|
||||
@doc = WithCallBacks.new
|
||||
end
|
||||
|
||||
|
||||
describe "validate" do
|
||||
it "should run before_validate before validating" do
|
||||
@doc.run_before_validate.should be_nil
|
||||
@doc.should be_valid
|
||||
@doc.run_before_validate.should be_true
|
||||
end
|
||||
it "should run after_validate after validating" do
|
||||
@doc.run_after_validate.should be_nil
|
||||
@doc.should be_valid
|
||||
@doc.run_after_validate.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "save" do
|
||||
it "should run the after filter after saving" do
|
||||
@doc.run_after_save.should be_nil
|
||||
@doc.save.should be_true
|
||||
@doc.run_after_save.should be_true
|
||||
end
|
||||
it "should run the grouped callbacks before saving" do
|
||||
@doc.run_one.should be_nil
|
||||
@doc.run_two.should be_nil
|
||||
@doc.run_three.should be_nil
|
||||
@doc.save.should be_true
|
||||
@doc.run_one.should be_true
|
||||
@doc.run_two.should be_true
|
||||
@doc.run_three.should be_true
|
||||
end
|
||||
it "should not run conditional callbacks" do
|
||||
@doc.run_it = false
|
||||
@doc.save.should be_true
|
||||
@doc.conditional_one.should be_nil
|
||||
@doc.conditional_two.should be_nil
|
||||
end
|
||||
it "should run conditional callbacks" do
|
||||
@doc.run_it = true
|
||||
@doc.save.should be_true
|
||||
@doc.conditional_one.should be_true
|
||||
@doc.conditional_two.should be_true
|
||||
end
|
||||
end
|
||||
describe "create" do
|
||||
it "should run the before save filter when creating" do
|
||||
@doc.run_before_save.should be_nil
|
||||
@doc.create.should_not be_nil
|
||||
@doc.run_before_save.should be_true
|
||||
end
|
||||
it "should run the before create filter" do
|
||||
@doc.run_before_create.should be_nil
|
||||
@doc.create.should_not be_nil
|
||||
@doc.create
|
||||
@doc.run_before_create.should be_true
|
||||
end
|
||||
it "should run the after create filter" do
|
||||
@doc.run_after_create.should be_nil
|
||||
@doc.create.should_not be_nil
|
||||
@doc.create
|
||||
@doc.run_after_create.should be_true
|
||||
end
|
||||
end
|
||||
describe "update" do
|
||||
|
||||
before(:each) do
|
||||
@doc.save
|
||||
end
|
||||
it "should run the before update filter when updating an existing document" do
|
||||
@doc.run_before_update.should be_nil
|
||||
@doc.update
|
||||
@doc.run_before_update.should be_true
|
||||
end
|
||||
it "should run the after update filter when updating an existing document" do
|
||||
@doc.run_after_update.should be_nil
|
||||
@doc.update
|
||||
@doc.run_after_update.should be_true
|
||||
end
|
||||
it "should run the before update filter when saving an existing document" do
|
||||
@doc.run_before_update.should be_nil
|
||||
@doc.save
|
||||
@doc.run_before_update.should be_true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
describe "getter and setter methods" do
|
||||
it "should try to call the arg= method before setting :arg in the hash" do
|
||||
@doc = WithGetterAndSetterMethods.new(:arg => "foo")
|
||||
@doc['arg'].should be_nil
|
||||
@doc[:arg].should be_nil
|
||||
@doc.other_arg.should == "foo-foo"
|
||||
end
|
||||
end
|
||||
|
||||
describe "initialization" do
|
||||
it "should call after_initialize method if available" do
|
||||
@doc = WithAfterInitializeMethod.new
|
||||
@doc['some_value'].should eql('value')
|
||||
end
|
||||
end
|
||||
|
||||
describe "recursive validation on an extended document" do
|
||||
before :each do
|
||||
reset_test_db!
|
||||
@cat = Cat.new(:name => 'Sockington')
|
||||
end
|
||||
|
||||
it "should not save if a nested casted model is invalid" do
|
||||
@cat.favorite_toy = CatToy.new
|
||||
@cat.should_not be_valid
|
||||
@cat.save.should be_false
|
||||
lambda{@cat.save!}.should raise_error
|
||||
end
|
||||
|
||||
it "should save when nested casted model is valid" do
|
||||
@cat.favorite_toy = CatToy.new(:name => 'Squeaky')
|
||||
@cat.should be_valid
|
||||
@cat.save.should be_true
|
||||
lambda{@cat.save!}.should_not raise_error
|
||||
end
|
||||
|
||||
it "should not save when nested collection contains an invalid casted model" do
|
||||
@cat.toys = [CatToy.new(:name => 'Feather'), CatToy.new]
|
||||
@cat.should_not be_valid
|
||||
@cat.save.should be_false
|
||||
lambda{@cat.save!}.should raise_error
|
||||
end
|
||||
|
||||
it "should save when nested collection contains valid casted models" do
|
||||
@cat.toys = [CatToy.new(:name => 'feather'), CatToy.new(:name => 'ball-o-twine')]
|
||||
@cat.should be_valid
|
||||
@cat.save.should be_true
|
||||
lambda{@cat.save!}.should_not raise_error
|
||||
end
|
||||
|
||||
it "should not fail if the nested casted model doesn't have validation" do
|
||||
Cat.property :trainer, :cast_as => 'Person'
|
||||
Cat.validates_presence_of :name
|
||||
cat = Cat.new(:name => 'Mr Bigglesworth')
|
||||
cat.trainer = Person.new
|
||||
cat.trainer.validatable?.should be_false
|
||||
cat.should be_valid
|
||||
cat.save.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "searching the contents of an extended document" do
|
||||
before :each do
|
||||
@db = reset_test_db!
|
||||
|
||||
names = ["Fuzzy", "Whiskers", "Mr Bigglesworth", "Sockington", "Smitty", "Sammy", "Samson", "Simon"]
|
||||
names.each { |name| Cat.create(:name => name) }
|
||||
|
||||
search_function = { 'defaults' => {'store' => 'no', 'index' => 'analyzed_no_norms'},
|
||||
'index' => "function(doc) { ret = new Document(); ret.add(doc['name'], {'field':'name'}); return ret; }" }
|
||||
@db.save_doc({'_id' => '_design/search', 'fulltext' => {'cats' => search_function}})
|
||||
end
|
||||
|
||||
it "should be able to paginate through a large set of search results" do
|
||||
if couchdb_lucene_available?
|
||||
names = []
|
||||
Cat.paginated_each(:design_doc => "search", :view_name => "cats",
|
||||
:q => 'name:S*', :search => true, :include_docs => true, :per_page => 3) do |cat|
|
||||
cat.should_not be_nil
|
||||
names << cat.name
|
||||
end
|
||||
|
||||
names.size.should == 5
|
||||
names.should include('Sockington')
|
||||
names.should include('Smitty')
|
||||
names.should include('Sammy')
|
||||
names.should include('Samson')
|
||||
names.should include('Simon')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -13,7 +13,7 @@ begin
|
|||
class PlainChild < PlainParent
|
||||
end
|
||||
|
||||
class ExtendedParent < CouchRest::ExtendedDocument
|
||||
class ExtendedParent < CouchRest::Model::Base
|
||||
class_inheritable_accessor :foo
|
||||
self.foo = :bar
|
||||
end
|
409
spec/couchrest/persistence_spec.rb
Normal file
409
spec/couchrest/persistence_spec.rb
Normal file
|
@ -0,0 +1,409 @@
|
|||
# encoding: utf-8
|
||||
require File.expand_path('../../spec_helper', __FILE__)
|
||||
require File.join(FIXTURE_PATH, 'base')
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||
|
||||
describe "Model Persistence" do
|
||||
|
||||
before(:each) do
|
||||
@obj = WithDefaultValues.new
|
||||
end
|
||||
|
||||
describe "creating a new document from database" do
|
||||
|
||||
it "should instantialize" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem1', '_rev' => 123, 'couchrest-type' => 'Article', 'name' => 'my test'})
|
||||
doc.class.should eql(Article)
|
||||
end
|
||||
|
||||
it "should instantialize of same class if no couchrest-type included from DB" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem1', '_rev' => 123, 'name' => 'my test'})
|
||||
doc.class.should eql(Article)
|
||||
end
|
||||
|
||||
it "should instantialize document of different type" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem2', '_rev' => 123, 'couchrest-type' => 'WithTemplateAndUniqueID', 'name' => 'my test'})
|
||||
doc.class.should eql(WithTemplateAndUniqueID)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "basic saving and retrieving" do
|
||||
it "should work fine" do
|
||||
@obj.name = "should be easily saved and retrieved"
|
||||
@obj.save
|
||||
saved_obj = WithDefaultValues.get(@obj.id)
|
||||
saved_obj.should_not be_nil
|
||||
end
|
||||
|
||||
it "should parse the Time attributes automatically" do
|
||||
@obj.name = "should parse the Time attributes automatically"
|
||||
@obj.set_by_proc.should be_an_instance_of(Time)
|
||||
@obj.save
|
||||
@obj.set_by_proc.should be_an_instance_of(Time)
|
||||
saved_obj = WithDefaultValues.get(@obj.id)
|
||||
saved_obj.set_by_proc.should be_an_instance_of(Time)
|
||||
end
|
||||
end
|
||||
|
||||
describe "creating a model" do
|
||||
|
||||
before(:each) do
|
||||
@sobj = Basic.new
|
||||
end
|
||||
|
||||
it "should accept true or false on save for validation" do
|
||||
@sobj.should_receive(:valid?)
|
||||
@sobj.save(true)
|
||||
end
|
||||
|
||||
it "should accept hash with validation option" do
|
||||
@sobj.should_receive(:valid?)
|
||||
@sobj.save(:validate => true)
|
||||
end
|
||||
|
||||
it "should not call validation when option is false" do
|
||||
@sobj.should_not_receive(:valid?)
|
||||
@sobj.save(false)
|
||||
end
|
||||
|
||||
it "should not call validation when option :validate is false" do
|
||||
@sobj.should_not_receive(:valid?)
|
||||
@sobj.save(:validate => false)
|
||||
end
|
||||
|
||||
it "should instantialize and save a document" do
|
||||
article = Article.create(:title => 'my test')
|
||||
article.title.should == 'my test'
|
||||
article.should_not be_new
|
||||
end
|
||||
|
||||
it "should trigger the create callbacks" do
|
||||
doc = WithCallBacks.create(:name => 'my other test')
|
||||
doc.run_before_create.should be_true
|
||||
doc.run_after_create.should be_true
|
||||
doc.run_before_save.should be_true
|
||||
doc.run_after_save.should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "saving a model" do
|
||||
before(:all) do
|
||||
@sobj = Basic.new
|
||||
@sobj.save.should be_true
|
||||
end
|
||||
|
||||
it "should save the doc" do
|
||||
doc = Basic.get(@sobj.id)
|
||||
doc['_id'].should == @sobj.id
|
||||
end
|
||||
|
||||
it "should be set for resaving" do
|
||||
rev = @obj.rev
|
||||
@sobj['another-key'] = "some value"
|
||||
@sobj.save
|
||||
@sobj.rev.should_not == rev
|
||||
end
|
||||
|
||||
it "should set the id" do
|
||||
@sobj.id.should be_an_instance_of(String)
|
||||
end
|
||||
|
||||
it "should set the type" do
|
||||
@sobj['couchrest-type'].should == 'Basic'
|
||||
end
|
||||
|
||||
it "should accept true or false on save for validation" do
|
||||
@sobj.should_receive(:valid?)
|
||||
@sobj.save(true)
|
||||
end
|
||||
|
||||
it "should accept hash with validation option" do
|
||||
@sobj.should_receive(:valid?)
|
||||
@sobj.save(:validate => true)
|
||||
end
|
||||
|
||||
it "should not call validation when option is false" do
|
||||
@sobj.should_not_receive(:valid?)
|
||||
@sobj.save(false)
|
||||
end
|
||||
|
||||
it "should not call validation when option :validate is false" do
|
||||
@sobj.should_not_receive(:valid?)
|
||||
@sobj.save(:validate => false)
|
||||
end
|
||||
|
||||
describe "save!" do
|
||||
|
||||
before(:each) do
|
||||
@sobj = Card.new(:first_name => "Marcos", :last_name => "Tapajós")
|
||||
end
|
||||
|
||||
it "should return true if save the document" do
|
||||
@sobj.save!.should be_true
|
||||
end
|
||||
|
||||
it "should raise error if don't save the document" do
|
||||
@sobj.first_name = nil
|
||||
lambda { @sobj.save! }.should raise_error(CouchRest::Model::Errors::Validations)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
describe "saving a model with a unique_id configured" do
|
||||
before(:each) do
|
||||
@art = Article.new
|
||||
@old = Article.database.get('this-is-the-title') rescue nil
|
||||
Article.database.delete_doc(@old) if @old
|
||||
end
|
||||
|
||||
it "should be a new document" do
|
||||
@art.should be_new
|
||||
@art.title.should be_nil
|
||||
end
|
||||
|
||||
it "should require the title" do
|
||||
lambda{@art.save}.should raise_error
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should be_true
|
||||
end
|
||||
|
||||
it "should not change the slug on update" do
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should be_true
|
||||
@art.title = 'new title'
|
||||
@art.save.should be_true
|
||||
@art.slug.should == 'this-is-the-title'
|
||||
end
|
||||
|
||||
it "should raise an error when the slug is taken" do
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should be_true
|
||||
@art2 = Article.new(:title => 'This is the title!')
|
||||
lambda{@art2.save}.should raise_error
|
||||
end
|
||||
|
||||
it "should set the slug" do
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should be_true
|
||||
@art.slug.should == 'this-is-the-title'
|
||||
end
|
||||
|
||||
it "should set the id" do
|
||||
@art.title = 'This is the title'
|
||||
@art.save.should be_true
|
||||
@art.id.should == 'this-is-the-title'
|
||||
end
|
||||
end
|
||||
|
||||
describe "saving a model with a unique_id lambda" do
|
||||
before(:each) do
|
||||
@templated = WithTemplateAndUniqueID.new
|
||||
@old = WithTemplateAndUniqueID.get('very-important') rescue nil
|
||||
@old.destroy if @old
|
||||
end
|
||||
|
||||
it "should require the field" do
|
||||
lambda{@templated.save}.should raise_error
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should be_true
|
||||
end
|
||||
|
||||
it "should save with the id" do
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should be_true
|
||||
t = WithTemplateAndUniqueID.get('very-important')
|
||||
t.should == @templated
|
||||
end
|
||||
|
||||
it "should not change the id on update" do
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should be_true
|
||||
@templated['important-field'] = 'not-important'
|
||||
@templated.save.should be_true
|
||||
t = WithTemplateAndUniqueID.get('very-important')
|
||||
t.should == @templated
|
||||
end
|
||||
|
||||
it "should raise an error when the id is taken" do
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should be_true
|
||||
lambda{WithTemplateAndUniqueID.new('important-field' => 'very-important').save}.should raise_error
|
||||
end
|
||||
|
||||
it "should set the id" do
|
||||
@templated['important-field'] = 'very-important'
|
||||
@templated.save.should be_true
|
||||
@templated.id.should == 'very-important'
|
||||
end
|
||||
end
|
||||
|
||||
describe "destroying an instance" do
|
||||
before(:each) do
|
||||
@dobj = Basic.new
|
||||
@dobj.save.should be_true
|
||||
end
|
||||
it "should return true" do
|
||||
result = @dobj.destroy
|
||||
result.should be_true
|
||||
end
|
||||
it "should be resavable" do
|
||||
@dobj.destroy
|
||||
@dobj.rev.should be_nil
|
||||
@dobj.id.should be_nil
|
||||
@dobj.save.should be_true
|
||||
end
|
||||
it "should make it go away" do
|
||||
@dobj.destroy
|
||||
lambda{Basic.get!(@dobj.id)}.should raise_error
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "getting a model" do
|
||||
before(:all) do
|
||||
@art = Article.new(:title => 'All About Getting')
|
||||
@art.save
|
||||
end
|
||||
it "should load and instantiate it" do
|
||||
foundart = Article.get @art.id
|
||||
foundart.title.should == "All About Getting"
|
||||
end
|
||||
it "should load and instantiate with find" do
|
||||
foundart = Article.find @art.id
|
||||
foundart.title.should == "All About Getting"
|
||||
end
|
||||
it "should return nil if `get` is used and the document doesn't exist" do
|
||||
foundart = Article.get 'matt aimonetti'
|
||||
foundart.should be_nil
|
||||
end
|
||||
it "should raise an error if `get!` is used and the document doesn't exist" do
|
||||
lambda{foundart = Article.get!('matt aimonetti')}.should raise_error
|
||||
end
|
||||
it "should raise an error if `find!` is used and the document doesn't exist" do
|
||||
lambda{foundart = Article.find!('matt aimonetti')}.should raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe "getting a model with a subobjects array" do
|
||||
before(:all) do
|
||||
course_doc = {
|
||||
"title" => "Metaphysics 200",
|
||||
"questions" => [
|
||||
{
|
||||
"q" => "Carve the ___ of reality at the ___.",
|
||||
"a" => ["beast","joints"]
|
||||
},{
|
||||
"q" => "Who layed the smack down on Leibniz's Law?",
|
||||
"a" => "Willard Van Orman Quine"
|
||||
}
|
||||
]
|
||||
}
|
||||
r = Course.database.save_doc course_doc
|
||||
@course = Course.get r['id']
|
||||
end
|
||||
it "should load the course" do
|
||||
@course.title.should == "Metaphysics 200"
|
||||
end
|
||||
it "should instantiate them as such" do
|
||||
@course["questions"][0].a[0].should == "beast"
|
||||
end
|
||||
end
|
||||
|
||||
describe "callbacks" do
|
||||
|
||||
before(:each) do
|
||||
@doc = WithCallBacks.new
|
||||
end
|
||||
|
||||
describe "validation" do
|
||||
it "should run before_validation before validating" do
|
||||
@doc.run_before_validate.should be_nil
|
||||
@doc.should be_valid
|
||||
@doc.run_before_validate.should be_true
|
||||
end
|
||||
it "should run after_validation after validating" do
|
||||
@doc.run_after_validate.should be_nil
|
||||
@doc.should be_valid
|
||||
@doc.run_after_validate.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "save" do
|
||||
it "should run the after filter after saving" do
|
||||
@doc.run_after_save.should be_nil
|
||||
@doc.save.should be_true
|
||||
@doc.run_after_save.should be_true
|
||||
end
|
||||
it "should run the grouped callbacks before saving" do
|
||||
@doc.run_one.should be_nil
|
||||
@doc.run_two.should be_nil
|
||||
@doc.run_three.should be_nil
|
||||
@doc.save.should be_true
|
||||
@doc.run_one.should be_true
|
||||
@doc.run_two.should be_true
|
||||
@doc.run_three.should be_true
|
||||
end
|
||||
it "should not run conditional callbacks" do
|
||||
@doc.run_it = false
|
||||
@doc.save.should be_true
|
||||
@doc.conditional_one.should be_nil
|
||||
@doc.conditional_two.should be_nil
|
||||
end
|
||||
it "should run conditional callbacks" do
|
||||
@doc.run_it = true
|
||||
@doc.save.should be_true
|
||||
@doc.conditional_one.should be_true
|
||||
@doc.conditional_two.should be_true
|
||||
end
|
||||
end
|
||||
describe "create" do
|
||||
it "should run the before save filter when creating" do
|
||||
@doc.run_before_save.should be_nil
|
||||
@doc.create.should_not be_nil
|
||||
@doc.run_before_save.should be_true
|
||||
end
|
||||
it "should run the before create filter" do
|
||||
@doc.run_before_create.should be_nil
|
||||
@doc.create.should_not be_nil
|
||||
@doc.create
|
||||
@doc.run_before_create.should be_true
|
||||
end
|
||||
it "should run the after create filter" do
|
||||
@doc.run_after_create.should be_nil
|
||||
@doc.create.should_not be_nil
|
||||
@doc.create
|
||||
@doc.run_after_create.should be_true
|
||||
end
|
||||
end
|
||||
describe "update" do
|
||||
|
||||
before(:each) do
|
||||
@doc.save
|
||||
end
|
||||
it "should run the before update filter when updating an existing document" do
|
||||
@doc.run_before_update.should be_nil
|
||||
@doc.update
|
||||
@doc.run_before_update.should be_true
|
||||
end
|
||||
it "should run the after update filter when updating an existing document" do
|
||||
@doc.run_after_update.should be_nil
|
||||
@doc.update
|
||||
@doc.run_after_update.should be_true
|
||||
end
|
||||
it "should run the before update filter when saving an existing document" do
|
||||
@doc.run_before_update.should be_nil
|
||||
@doc.save
|
||||
@doc.run_before_update.should be_true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -1,16 +1,16 @@
|
|||
# encoding: utf-8
|
||||
require File.expand_path('../../spec_helper', __FILE__)
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||
require File.join(FIXTURE_PATH, 'more', 'invoice')
|
||||
require File.join(FIXTURE_PATH, 'more', 'service')
|
||||
require File.join(FIXTURE_PATH, 'more', 'event')
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
require File.join(FIXTURE_PATH, 'more', 'user')
|
||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||
|
||||
|
||||
describe "ExtendedDocument properties" do
|
||||
describe "Model properties" do
|
||||
|
||||
before(:each) do
|
||||
reset_test_db!
|
||||
|
@ -134,27 +134,27 @@ describe "ExtendedDocument properties" do
|
|||
@card.first_name = nil
|
||||
@card.should_not be_valid
|
||||
@card.errors.should_not be_empty
|
||||
@card.errors.on(:first_name).should == ["First name must not be blank"]
|
||||
@card.errors[:first_name].should == ["can't be blank"]
|
||||
end
|
||||
|
||||
it "should let you look up errors for a field by a string name" do
|
||||
@card.first_name = nil
|
||||
@card.should_not be_valid
|
||||
@card.errors.on('first_name').should == ["First name must not be blank"]
|
||||
@card.errors['first_name'].should == ["can't be blank"]
|
||||
end
|
||||
|
||||
it "should validate the presence of 2 attributes" do
|
||||
@invoice.clear
|
||||
@invoice.should_not be_valid
|
||||
@invoice.errors.should_not be_empty
|
||||
@invoice.errors.on(:client_name).first.should == "Client name must not be blank"
|
||||
@invoice.errors.on(:employee_name).should_not be_empty
|
||||
@invoice.errors[:client_name].should == ["can't be blank"]
|
||||
@invoice.errors[:employee_name].should_not be_empty
|
||||
end
|
||||
|
||||
it "should let you set an error message" do
|
||||
@invoice.location = nil
|
||||
@invoice.valid?
|
||||
@invoice.errors.on(:location).should == ["Hey stupid!, you forgot the location"]
|
||||
@invoice.errors[:location].should == ["Hey stupid!, you forgot the location"]
|
||||
end
|
||||
|
||||
it "should validate before saving" do
|
||||
|
@ -165,37 +165,6 @@ describe "ExtendedDocument properties" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "autovalidation" do
|
||||
before(:each) do
|
||||
@service = Service.new(:name => "Coumpound analysis", :price => 3_000)
|
||||
end
|
||||
|
||||
it "should be valid" do
|
||||
@service.should be_valid
|
||||
end
|
||||
|
||||
it "should not respond to properties not setup" do
|
||||
@service.respond_to?(:client_name).should be_false
|
||||
end
|
||||
|
||||
describe "property :name, :length => 4...20" do
|
||||
|
||||
it "should autovalidate the presence when length is set" do
|
||||
@service.name = nil
|
||||
@service.should_not be_valid
|
||||
@service.errors.should_not be_nil
|
||||
@service.errors.on(:name).first.should == "Name must be between 4 and 19 characters long"
|
||||
end
|
||||
|
||||
it "should autovalidate the correct length" do
|
||||
@service.name = "a"
|
||||
@service.should_not be_valid
|
||||
@service.errors.should_not be_nil
|
||||
@service.errors.on(:name).first.should == "Name must be between 4 and 19 characters long"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "casting" do
|
||||
before(:each) do
|
||||
@course = Course.new(:title => 'Relaxation')
|
||||
|
@ -740,50 +709,43 @@ end
|
|||
describe "Property Class" do
|
||||
|
||||
it "should provide name as string" do
|
||||
property = CouchRest::Property.new(:test, String)
|
||||
property = CouchRest::Model::Property.new(:test, String)
|
||||
property.name.should eql('test')
|
||||
property.to_s.should eql('test')
|
||||
end
|
||||
|
||||
it "should provide class from type" do
|
||||
property = CouchRest::Property.new(:test, String)
|
||||
property = CouchRest::Model::Property.new(:test, String)
|
||||
property.type_class.should eql(String)
|
||||
end
|
||||
|
||||
it "should provide base class from type in array" do
|
||||
property = CouchRest::Property.new(:test, [String])
|
||||
property = CouchRest::Model::Property.new(:test, [String])
|
||||
property.type_class.should eql(String)
|
||||
end
|
||||
|
||||
it "should leave type as string if requested" do
|
||||
property = CouchRest::Property.new(:test, 'String')
|
||||
property.type.should eql('String')
|
||||
property.type_class.should eql(String)
|
||||
it "should raise error if type as string requested" do
|
||||
lambda {
|
||||
property = CouchRest::Model::Property.new(:test, 'String')
|
||||
}.should raise_error
|
||||
end
|
||||
|
||||
it "should leave type nil and return string by default" do
|
||||
property = CouchRest::Property.new(:test, nil)
|
||||
it "should leave type nil and return class as nil also" do
|
||||
property = CouchRest::Model::Property.new(:test, nil)
|
||||
property.type.should be_nil
|
||||
# Type cast should never be used on non-casted property!
|
||||
property.type_class.should eql(String)
|
||||
property.type_class.should be_nil
|
||||
end
|
||||
|
||||
it "should convert empty type array to [String]" do
|
||||
property = CouchRest::Property.new(:test, [])
|
||||
property.type_class.should eql(String)
|
||||
end
|
||||
|
||||
it "should convert boolean text-type TrueClass" do
|
||||
property = CouchRest::Property.new(:test, 'boolean')
|
||||
property.type.should eql('boolean') # no change
|
||||
property.type_class.should eql(TrueClass)
|
||||
it "should convert empty type array to [Object]" do
|
||||
property = CouchRest::Model::Property.new(:test, [])
|
||||
property.type_class.should eql(Object)
|
||||
end
|
||||
|
||||
it "should set init method option or leave as 'new'" do
|
||||
# (bad example! Time already typecast)
|
||||
property = CouchRest::Property.new(:test, Time)
|
||||
property = CouchRest::Model::Property.new(:test, Time)
|
||||
property.init_method.should eql('new')
|
||||
property = CouchRest::Property.new(:test, Time, :init_method => 'parse')
|
||||
property = CouchRest::Model::Property.new(:test, Time, :init_method => 'parse')
|
||||
property.init_method.should eql('parse')
|
||||
end
|
||||
|
||||
|
@ -791,32 +753,32 @@ describe "Property Class" do
|
|||
|
||||
describe "casting" do
|
||||
it "should cast a value" do
|
||||
property = CouchRest::Property.new(:test, Date)
|
||||
property = CouchRest::Model::Property.new(:test, Date)
|
||||
parent = mock("FooObject")
|
||||
property.cast(parent, "2010-06-16").should eql(Date.new(2010, 6, 16))
|
||||
property.cast_value(parent, "2010-06-16").should eql(Date.new(2010, 6, 16))
|
||||
end
|
||||
|
||||
it "should cast an array of values" do
|
||||
property = CouchRest::Property.new(:test, [Date])
|
||||
property = CouchRest::Model::Property.new(:test, [Date])
|
||||
parent = mock("FooObject")
|
||||
property.cast(parent, ["2010-06-01", "2010-06-02"]).should eql([Date.new(2010, 6, 1), Date.new(2010, 6, 2)])
|
||||
end
|
||||
|
||||
it "should set a CastedArray on array of Objects" do
|
||||
property = CouchRest::Property.new(:test, [Object])
|
||||
property = CouchRest::Model::Property.new(:test, [Object])
|
||||
parent = mock("FooObject")
|
||||
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should eql(::CouchRest::CastedArray)
|
||||
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should eql(CouchRest::Model::CastedArray)
|
||||
end
|
||||
|
||||
it "should not set a CastedArray on array of Strings" do
|
||||
property = CouchRest::Property.new(:test, [String])
|
||||
property = CouchRest::Model::Property.new(:test, [String])
|
||||
parent = mock("FooObject")
|
||||
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should_not eql(::CouchRest::CastedArray)
|
||||
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should_not eql(CouchRest::Model::CastedArray)
|
||||
end
|
||||
|
||||
it "should raise and error if value is array when type is not" do
|
||||
property = CouchRest::Property.new(:test, Date)
|
||||
property = CouchRest::Model::Property.new(:test, Date)
|
||||
parent = mock("FooClass")
|
||||
lambda {
|
||||
cast = property.cast(parent, [Date.new(2010, 6, 1)])
|
||||
|
@ -825,13 +787,13 @@ describe "Property Class" do
|
|||
|
||||
|
||||
it "should set parent as casted_by object in CastedArray" do
|
||||
property = CouchRest::Property.new(:test, [Object])
|
||||
property = CouchRest::Model::Property.new(:test, [Object])
|
||||
parent = mock("FooObject")
|
||||
property.cast(parent, ["2010-06-01", "2010-06-02"]).casted_by.should eql(parent)
|
||||
end
|
||||
|
||||
it "should set casted_by on new value" do
|
||||
property = CouchRest::Property.new(:test, CatToy)
|
||||
property = CouchRest::Model::Property.new(:test, CatToy)
|
||||
parent = mock("CatObject")
|
||||
cast = property.cast(parent, {:name => 'catnip'})
|
||||
cast.casted_by.should eql(parent)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require File.expand_path("../../spec_helper", __FILE__)
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||
|
@ -9,6 +10,9 @@ Card.property :bg_color, :default => '#ccc'
|
|||
class BusinessCard < Card
|
||||
property :extension_code
|
||||
property :job_title
|
||||
|
||||
validates_presence_of :extension_code
|
||||
validates_presence_of :job_title
|
||||
end
|
||||
|
||||
class DesignBusinessCard < BusinessCard
|
||||
|
@ -20,7 +24,7 @@ class OnlineCourse < Course
|
|||
view_by :url
|
||||
end
|
||||
|
||||
class Animal < CouchRest::ExtendedDocument
|
||||
class Animal < CouchRest::Model::Base
|
||||
use_database TEST_SERVER.default_database
|
||||
property :name
|
||||
view_by :name
|
||||
|
@ -28,7 +32,7 @@ end
|
|||
|
||||
class Dog < Animal; end
|
||||
|
||||
describe "Subclassing an ExtendedDocument" do
|
||||
describe "Subclassing a Model" do
|
||||
|
||||
before(:each) do
|
||||
@card = BusinessCard.new
|
||||
|
@ -42,22 +46,18 @@ describe "Subclassing an ExtendedDocument" do
|
|||
@card.database.uri.should == Card.database.uri
|
||||
end
|
||||
|
||||
it "should share the same autovalidation details" do
|
||||
@card.auto_validation.should be_true
|
||||
end
|
||||
|
||||
it "should have kept the validation details" do
|
||||
@card.should_not be_valid
|
||||
end
|
||||
|
||||
it "should have added the new validation details" do
|
||||
validated_fields = @card.class.validators.contexts[:default].map{|v| v.field_name}
|
||||
validated_fields.should include(:extension_code)
|
||||
validated_fields = @card.class.validators.map{|v| v.attributes}.flatten
|
||||
validated_fields.should include(:extension_code)
|
||||
validated_fields.should include(:job_title)
|
||||
end
|
||||
|
||||
it "should not add to the parent's validations" do
|
||||
validated_fields = Card.validators.contexts[:default].map{|v| v.field_name}
|
||||
validated_fields = Card.validators.map{|v| v.attributes}.flatten
|
||||
validated_fields.should_not include(:extension_code)
|
||||
validated_fields.should_not include(:job_title)
|
||||
end
|
|
@ -1,10 +1,12 @@
|
|||
require File.expand_path("../../spec_helper", __FILE__)
|
||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||
|
||||
describe "ExtendedDocument views" do
|
||||
describe "Model views" do
|
||||
|
||||
class Unattached < CouchRest::ExtendedDocument
|
||||
class Unattached < CouchRest::Model::Base
|
||||
# Note: no use_database here
|
||||
property :title
|
||||
property :questions
|
||||
|
@ -438,7 +440,7 @@ describe "ExtendedDocument views" do
|
|||
it "should pass database parameter to pager" do
|
||||
proxy = mock(:proxy)
|
||||
proxy.stub!(:paginate)
|
||||
::CouchRest::Mixins::Collection::CollectionProxy.should_receive(:new).with('database', anything(), anything(), anything(), anything()).and_return(proxy)
|
||||
::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
|
Loading…
Add table
Add a link
Reference in a new issue