Merge branch 'master' of git://github.com/couchrest/couchrest_model
This commit is contained in:
commit
9f7ce5d49b
|
@ -23,11 +23,12 @@ Gem::Specification.new do |s|
|
||||||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||||
s.require_paths = ["lib"]
|
s.require_paths = ["lib"]
|
||||||
|
|
||||||
s.add_dependency(%q<couchrest>, "1.1.0.pre2")
|
s.add_dependency(%q<couchrest>, "1.1.0.pre3")
|
||||||
s.add_dependency(%q<mime-types>, "~> 1.15")
|
s.add_dependency(%q<mime-types>, "~> 1.15")
|
||||||
s.add_dependency(%q<activemodel>, "~> 3.0")
|
s.add_dependency(%q<activemodel>, "~> 3.0")
|
||||||
s.add_dependency(%q<tzinfo>, "~> 0.3.22")
|
s.add_dependency(%q<tzinfo>, "~> 0.3.22")
|
||||||
s.add_development_dependency(%q<rspec>, ">= 2.0.0")
|
s.add_development_dependency(%q<rspec>, "~> 2.6.0")
|
||||||
|
s.add_development_dependency(%q<json>, ["~> 1.5.1"])
|
||||||
s.add_development_dependency(%q<rack-test>, ">= 0.5.7")
|
s.add_development_dependency(%q<rack-test>, ">= 0.5.7")
|
||||||
# s.add_development_dependency("jruby-openssl", ">= 0.7.3")
|
# s.add_development_dependency("jruby-openssl", ">= 0.7.3")
|
||||||
end
|
end
|
||||||
|
|
17
history.md
17
history.md
|
@ -1,10 +1,18 @@
|
||||||
# CouchRest Model Change History
|
# CouchRest Model Change History
|
||||||
|
|
||||||
## 1.1.0 - 2011-05-XX
|
## 1.1.0 - 2011-06-XX
|
||||||
|
|
||||||
|
* Minor Fixes
|
||||||
|
* Validation callbacks now support context (thanks kostia)
|
||||||
|
* Document comparisons now performed using database and document ID (pointer by neocsr)
|
||||||
|
|
||||||
|
## 1.1.0.rc1 - 2011-06-08
|
||||||
|
|
||||||
* New Features
|
* New Features
|
||||||
* Properties with a nil value are now no longer sent to the database.
|
* Properties with a nil value are now no longer sent to the database.
|
||||||
* Now possible to build new objects via CastedArray#build
|
* Now possible to build new objects via CastedArray#build
|
||||||
|
* Implement #get! and #find! class methods
|
||||||
|
* Now is possible delete particular elements in casted array(Kostiantyn Kahanskyi)
|
||||||
|
|
||||||
* Minor fixes
|
* Minor fixes
|
||||||
* #as_json now correctly uses ActiveSupports methods.
|
* #as_json now correctly uses ActiveSupports methods.
|
||||||
|
@ -14,7 +22,12 @@
|
||||||
* DesignDoc cache refreshed if a database is deleted.
|
* DesignDoc cache refreshed if a database is deleted.
|
||||||
* Fixing dirty tracking on collection_of association.
|
* Fixing dirty tracking on collection_of association.
|
||||||
* Uniqueness Validation views created on initialization, not on demand!
|
* Uniqueness Validation views created on initialization, not on demand!
|
||||||
|
* #destroy freezes object instead of removing _id and _rev, better for callbacks (pointer by karmi)
|
||||||
|
* #destroyed? method now available
|
||||||
|
* #reload no longer uses Hash#merge! which was causing issues with dirty tracking on casted models. (pointer by kostia)
|
||||||
|
* Non-property mass assignment on #new no longer possible without :directly_set_attributes option.
|
||||||
|
* Using CouchRest 1.1.0.pre3. (No more Hashes!)
|
||||||
|
* Fixing problem assigning a CastedHash to a property declared as a Hash (Kostiantyn Kahanskyi, gfmtim)
|
||||||
|
|
||||||
## 1.1.0.beta5 - 2011-04-30
|
## 1.1.0.beta5 - 2011-04-30
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
module CouchRest
|
module CouchRest
|
||||||
module Model
|
module Model
|
||||||
class Base < Document
|
class Base < CouchRest::Document
|
||||||
|
|
||||||
extend ActiveModel::Naming
|
extend ActiveModel::Naming
|
||||||
|
|
||||||
include CouchRest::Model::Configuration
|
include CouchRest::Model::Configuration
|
||||||
include CouchRest::Model::Connection
|
include CouchRest::Model::Connection
|
||||||
include CouchRest::Model::Persistence
|
include CouchRest::Model::Persistence
|
||||||
include CouchRest::Model::Callbacks
|
|
||||||
include CouchRest::Model::DocumentQueries
|
include CouchRest::Model::DocumentQueries
|
||||||
include CouchRest::Model::Views
|
include CouchRest::Model::Views
|
||||||
include CouchRest::Model::DesignDoc
|
include CouchRest::Model::DesignDoc
|
||||||
|
@ -18,9 +17,11 @@ module CouchRest
|
||||||
include CouchRest::Model::PropertyProtection
|
include CouchRest::Model::PropertyProtection
|
||||||
include CouchRest::Model::Associations
|
include CouchRest::Model::Associations
|
||||||
include CouchRest::Model::Validations
|
include CouchRest::Model::Validations
|
||||||
|
include CouchRest::Model::Callbacks
|
||||||
include CouchRest::Model::Designs
|
include CouchRest::Model::Designs
|
||||||
include CouchRest::Model::CastedBy
|
include CouchRest::Model::CastedBy
|
||||||
include CouchRest::Model::Dirty
|
include CouchRest::Model::Dirty
|
||||||
|
include CouchRest::Model::Callbacks
|
||||||
|
|
||||||
def self.subclasses
|
def self.subclasses
|
||||||
@subclasses ||= []
|
@subclasses ||= []
|
||||||
|
@ -51,14 +52,15 @@ module CouchRest
|
||||||
#
|
#
|
||||||
# If a block is provided the new model will be passed into the
|
# If a block is provided the new model will be passed into the
|
||||||
# block so that it can be populated.
|
# block so that it can be populated.
|
||||||
def initialize(doc = {}, options = {})
|
def initialize(attributes = {}, options = {})
|
||||||
doc = prepare_all_attributes(doc, options)
|
super()
|
||||||
# set the instances database, if provided
|
prepare_all_attributes(attributes, options)
|
||||||
|
# set the instance's database, if provided
|
||||||
self.database = options[:database] unless options[:database].nil?
|
self.database = options[:database] unless options[:database].nil?
|
||||||
super(doc)
|
|
||||||
unless self['_id'] && self['_rev']
|
unless self['_id'] && self['_rev']
|
||||||
self[self.model_type_key] = self.class.to_s
|
self[self.model_type_key] = self.class.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
yield self if block_given?
|
yield self if block_given?
|
||||||
|
|
||||||
after_initialize if respond_to?(:after_initialize)
|
after_initialize if respond_to?(:after_initialize)
|
||||||
|
@ -79,18 +81,8 @@ module CouchRest
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
## Compatibility with ActiveSupport and older frameworks
|
|
||||||
|
|
||||||
# Hack so that CouchRest::Document, which descends from Hash,
|
|
||||||
# doesn't appear to Rails routing as a Hash of options
|
|
||||||
def is_a?(klass)
|
|
||||||
return false if klass == Hash
|
|
||||||
super
|
|
||||||
end
|
|
||||||
alias :kind_of? :is_a?
|
|
||||||
|
|
||||||
def persisted?
|
def persisted?
|
||||||
!new?
|
!new? && !destroyed?
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_key
|
def to_key
|
||||||
|
@ -100,6 +92,21 @@ module CouchRest
|
||||||
alias :to_param :id
|
alias :to_param :id
|
||||||
alias :new_record? :new?
|
alias :new_record? :new?
|
||||||
alias :new_document? :new?
|
alias :new_document? :new?
|
||||||
|
|
||||||
|
# Compare this model with another by confirming to see
|
||||||
|
# if the IDs and their databases match!
|
||||||
|
#
|
||||||
|
# Camparison of the database is required in case the
|
||||||
|
# model has been proxied or loaded elsewhere.
|
||||||
|
#
|
||||||
|
# A Basic CouchRest document will only ever compare using
|
||||||
|
# a Hash comparison on the attributes.
|
||||||
|
def == other
|
||||||
|
return false unless other.is_a?(Base)
|
||||||
|
database == other.database && id == other.id
|
||||||
|
end
|
||||||
|
alias :eql? :==
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,21 +5,23 @@ module CouchRest #:nodoc:
|
||||||
|
|
||||||
module Callbacks
|
module Callbacks
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
CALLBACKS = [
|
||||||
|
:before_validation, :after_validation,
|
||||||
|
:after_initialize,
|
||||||
|
:before_create, :around_create, :after_create,
|
||||||
|
:before_destroy, :around_destroy, :after_destroy,
|
||||||
|
:before_save, :around_save, :after_save,
|
||||||
|
:before_update, :around_update, :after_update,
|
||||||
|
]
|
||||||
|
|
||||||
included do
|
included do
|
||||||
extend ActiveModel::Callbacks
|
extend ActiveModel::Callbacks
|
||||||
|
include ActiveModel::Validations::Callbacks
|
||||||
|
|
||||||
define_model_callbacks \
|
define_model_callbacks :initialize, :only => :after
|
||||||
:create,
|
define_model_callbacks :create, :destroy, :save, :update
|
||||||
:destroy,
|
|
||||||
:save,
|
|
||||||
:update
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid?(*) #nodoc
|
|
||||||
_run_validation_callbacks { super }
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -50,6 +50,16 @@ module CouchRest::Model
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete(obj)
|
||||||
|
couchrest_parent_will_change! if use_dirty? && self.length > 0
|
||||||
|
super(obj)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_at(index)
|
||||||
|
couchrest_parent_will_change! if use_dirty? && self.length > 0
|
||||||
|
super(index)
|
||||||
|
end
|
||||||
|
|
||||||
def build(*args)
|
def build(*args)
|
||||||
obj = casted_by_property.build(*args)
|
obj = casted_by_property.build(*args)
|
||||||
self.push(obj)
|
self.push(obj)
|
||||||
|
|
|
@ -5,13 +5,15 @@ module CouchRest::Model
|
||||||
|
|
||||||
included do
|
included do
|
||||||
include CouchRest::Model::Configuration
|
include CouchRest::Model::Configuration
|
||||||
include CouchRest::Model::Callbacks
|
|
||||||
include CouchRest::Model::Properties
|
include CouchRest::Model::Properties
|
||||||
include CouchRest::Model::PropertyProtection
|
include CouchRest::Model::PropertyProtection
|
||||||
include CouchRest::Model::Associations
|
include CouchRest::Model::Associations
|
||||||
include CouchRest::Model::Validations
|
include CouchRest::Model::Validations
|
||||||
|
include CouchRest::Model::Callbacks
|
||||||
include CouchRest::Model::CastedBy
|
include CouchRest::Model::CastedBy
|
||||||
include CouchRest::Model::Dirty
|
include CouchRest::Model::Dirty
|
||||||
|
include CouchRest::Model::Callbacks
|
||||||
|
|
||||||
class_eval do
|
class_eval do
|
||||||
# Override CastedBy's base_doc?
|
# Override CastedBy's base_doc?
|
||||||
def base_doc?
|
def base_doc?
|
||||||
|
@ -42,7 +44,7 @@ module CouchRest::Model
|
||||||
alias :new_record? :new?
|
alias :new_record? :new?
|
||||||
|
|
||||||
def persisted?
|
def persisted?
|
||||||
!new?
|
!new? && !destroyed?
|
||||||
end
|
end
|
||||||
|
|
||||||
# The to_param method is needed for rails to generate resourceful routes.
|
# The to_param method is needed for rails to generate resourceful routes.
|
||||||
|
|
|
@ -88,6 +88,13 @@ module CouchRest
|
||||||
end
|
end
|
||||||
alias :find :get
|
alias :find :get
|
||||||
|
|
||||||
|
def get!(id)
|
||||||
|
doc = @klass.get!(id, @database)
|
||||||
|
doc.database = @database if doc && doc.respond_to?(:database)
|
||||||
|
doc
|
||||||
|
end
|
||||||
|
alias :find! :get!
|
||||||
|
|
||||||
# Views
|
# Views
|
||||||
|
|
||||||
def has_view?(view)
|
def has_view?(view)
|
||||||
|
|
|
@ -244,6 +244,7 @@ module CouchRest
|
||||||
else
|
else
|
||||||
options = { :limit => per_page, :skip => per_page * (page - 1) }
|
options = { :limit => per_page, :skip => per_page * (page - 1) }
|
||||||
end
|
end
|
||||||
|
options[:include_docs] = true
|
||||||
view_options.merge(options)
|
view_options.merge(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
module CouchRest
|
module CouchRest
|
||||||
module Model
|
module Model
|
||||||
module DocumentQueries
|
module DocumentQueries
|
||||||
|
extend ActiveSupport::Concern
|
||||||
def self.included(base)
|
|
||||||
base.extend(ClassMethods)
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
|
|
||||||
|
@ -86,9 +83,12 @@ module CouchRest
|
||||||
# id<String, Integer>:: Document ID
|
# id<String, Integer>:: Document ID
|
||||||
# db<Database>:: optional option to pass a custom database to use
|
# db<Database>:: optional option to pass a custom database to use
|
||||||
def get!(id, db = database)
|
def get!(id, db = database)
|
||||||
raise "Missing or empty document ID" if id.to_s.empty?
|
raise CouchRest::Model::DocumentNotFound if id.blank?
|
||||||
|
|
||||||
doc = db.get id
|
doc = db.get id
|
||||||
build_from_database(doc)
|
build_from_database(doc)
|
||||||
|
rescue RestClient::ResourceNotFound
|
||||||
|
raise CouchRest::Model::DocumentNotFound
|
||||||
end
|
end
|
||||||
alias :find! :get!
|
alias :find! :get!
|
||||||
|
|
||||||
|
|
|
@ -19,5 +19,7 @@ module CouchRest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class DocumentNotFound < Errors::CouchRestModelError; end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,8 +21,8 @@ module CouchRest
|
||||||
|
|
||||||
# Creates the document in the db. Raises an exception
|
# Creates the document in the db. Raises an exception
|
||||||
# if the document is not created properly.
|
# if the document is not created properly.
|
||||||
def create!
|
def create!(options = {})
|
||||||
self.class.fail_validate!(self) unless self.create
|
self.class.fail_validate!(self) unless self.create(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Trigger the callbacks (before, after, around)
|
# Trigger the callbacks (before, after, around)
|
||||||
|
@ -54,19 +54,21 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# Deletes the document from the database. Runs the :destroy callbacks.
|
# Deletes the document from the database. Runs the :destroy callbacks.
|
||||||
# Removes the <tt>_id</tt> and <tt>_rev</tt> fields, preparing the
|
|
||||||
# document to be saved to a new <tt>_id</tt> if required.
|
|
||||||
def destroy
|
def destroy
|
||||||
_run_destroy_callbacks do
|
_run_destroy_callbacks do
|
||||||
result = database.delete_doc(self)
|
result = database.delete_doc(self)
|
||||||
if result['ok']
|
if result['ok']
|
||||||
self.delete('_rev')
|
@_destroyed = true
|
||||||
self.delete('_id')
|
self.freeze
|
||||||
end
|
end
|
||||||
result['ok']
|
result['ok']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroyed?
|
||||||
|
!!@_destroyed
|
||||||
|
end
|
||||||
|
|
||||||
# Update the document's attributes and save. For example:
|
# Update the document's attributes and save. For example:
|
||||||
#
|
#
|
||||||
# doc.update_attributes :name => "Fred"
|
# doc.update_attributes :name => "Fred"
|
||||||
|
@ -85,7 +87,7 @@ module CouchRest
|
||||||
#
|
#
|
||||||
# Returns self.
|
# Returns self.
|
||||||
def reload
|
def reload
|
||||||
merge!(self.class.get(id))
|
prepare_all_attributes(database.get(id), :directly_set_attributes => true)
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -104,22 +106,25 @@ module CouchRest
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
|
|
||||||
# Creates a new instance, bypassing attribute protection
|
# Creates a new instance, bypassing attribute protection and
|
||||||
|
# uses the type field to determine which model to use to instanatiate
|
||||||
|
# the new object.
|
||||||
#
|
#
|
||||||
# ==== Returns
|
# ==== Returns
|
||||||
# a document instance
|
# a document instance
|
||||||
#
|
#
|
||||||
def build_from_database(doc = {})
|
def build_from_database(doc = {}, options = {}, &block)
|
||||||
base = (doc[model_type_key].blank? || doc[model_type_key] == self.to_s) ? self : doc[model_type_key].constantize
|
src = doc[model_type_key]
|
||||||
base.new(doc, :directly_set_attributes => true)
|
base = (src.blank? || src == self.to_s) ? self : src.constantize
|
||||||
|
base.new(doc, options.merge(:directly_set_attributes => true), &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Defines an instance and save it directly to the database
|
# Defines an instance and save it directly to the database
|
||||||
#
|
#
|
||||||
# ==== Returns
|
# ==== Returns
|
||||||
# returns the reloaded document
|
# returns the reloaded document
|
||||||
def create(attributes = {})
|
def create(attributes = {}, &block)
|
||||||
instance = new(attributes)
|
instance = new(attributes, &block)
|
||||||
instance.create
|
instance.create
|
||||||
instance
|
instance
|
||||||
end
|
end
|
||||||
|
@ -128,8 +133,8 @@ module CouchRest
|
||||||
#
|
#
|
||||||
# ==== Returns
|
# ==== Returns
|
||||||
# returns the reloaded document or raises an exception
|
# returns the reloaded document or raises an exception
|
||||||
def create!(attributes = {})
|
def create!(attributes = {}, &block)
|
||||||
instance = new(attributes)
|
instance = new(attributes, &block)
|
||||||
instance.create!
|
instance.create!
|
||||||
instance
|
instance
|
||||||
end
|
end
|
||||||
|
|
|
@ -80,17 +80,18 @@ module CouchRest
|
||||||
self.disable_dirty = dirty
|
self.disable_dirty = dirty
|
||||||
end
|
end
|
||||||
|
|
||||||
def prepare_all_attributes(doc = {}, options = {})
|
def prepare_all_attributes(attrs = {}, options = {})
|
||||||
self.disable_dirty = !!options[:directly_set_attributes]
|
self.disable_dirty = !!options[:directly_set_attributes]
|
||||||
apply_all_property_defaults
|
apply_all_property_defaults
|
||||||
if options[:directly_set_attributes]
|
if options[:directly_set_attributes]
|
||||||
directly_set_read_only_attributes(doc)
|
directly_set_read_only_attributes(attrs)
|
||||||
|
directly_set_attributes(attrs, true)
|
||||||
else
|
else
|
||||||
doc = remove_protected_attributes(doc)
|
attrs = remove_protected_attributes(attrs)
|
||||||
|
directly_set_attributes(attrs)
|
||||||
end
|
end
|
||||||
res = doc.nil? ? doc : directly_set_attributes(doc)
|
|
||||||
self.disable_dirty = false
|
self.disable_dirty = false
|
||||||
res
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_property!(property)
|
def find_property!(property)
|
||||||
|
@ -101,16 +102,13 @@ module CouchRest
|
||||||
|
|
||||||
# Set all the attributes and return a hash with the attributes
|
# Set all the attributes and return a hash with the attributes
|
||||||
# that have not been accepted.
|
# that have not been accepted.
|
||||||
def directly_set_attributes(hash)
|
def directly_set_attributes(hash, mass_assign = false)
|
||||||
hash.reject do |attribute_name, attribute_value|
|
return if hash.nil?
|
||||||
if self.respond_to?("#{attribute_name}=")
|
hash.reject do |key, value|
|
||||||
self.send("#{attribute_name}=", attribute_value)
|
if self.respond_to?("#{key}=")
|
||||||
true
|
self.send("#{key}=", value)
|
||||||
elsif mass_assign_any_attribute # config option
|
elsif mass_assign || mass_assign_any_attribute
|
||||||
self[attribute_name] = attribute_value
|
self[key] = value
|
||||||
true
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,19 +27,15 @@ module CouchRest::Model
|
||||||
if value.nil?
|
if value.nil?
|
||||||
value = []
|
value = []
|
||||||
elsif [Hash, HashWithIndifferentAccess].include?(value.class)
|
elsif [Hash, HashWithIndifferentAccess].include?(value.class)
|
||||||
# Assume provided as a Hash where key is index!
|
# Assume provided as a params hash where key is index
|
||||||
data = value
|
value = parameter_hash_to_array(value)
|
||||||
value = [ ]
|
|
||||||
data.keys.sort.each do |k|
|
|
||||||
value << data[k]
|
|
||||||
end
|
|
||||||
elsif !value.is_a?(Array)
|
elsif !value.is_a?(Array)
|
||||||
raise "Expecting an array or keyed hash for property #{parent.class.name}##{self.name}"
|
raise "Expecting an array or keyed hash for property #{parent.class.name}##{self.name}"
|
||||||
end
|
end
|
||||||
arr = value.collect { |data| cast_value(parent, data) }
|
arr = value.collect { |data| cast_value(parent, data) }
|
||||||
# allow casted_by calls to be passed up chain by wrapping in CastedArray
|
# allow casted_by calls to be passed up chain by wrapping in CastedArray
|
||||||
CastedArray.new(arr, self, parent)
|
CastedArray.new(arr, self, parent)
|
||||||
elsif (type == Object || type == Hash) && (value.class == Hash)
|
elsif (type == Object || type == Hash) && (value.is_a?(Hash))
|
||||||
# allow casted_by calls to be passed up chain by wrapping in CastedHash
|
# allow casted_by calls to be passed up chain by wrapping in CastedHash
|
||||||
CastedHash[value, self, parent]
|
CastedHash[value, self, parent]
|
||||||
elsif !value.nil?
|
elsif !value.nil?
|
||||||
|
@ -78,6 +74,14 @@ module CouchRest::Model
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def parameter_hash_to_array(source)
|
||||||
|
value = [ ]
|
||||||
|
source.keys.each do |k|
|
||||||
|
value[k.to_i] = source[k]
|
||||||
|
end
|
||||||
|
value.compact
|
||||||
|
end
|
||||||
|
|
||||||
def associate_casted_value_to_parent(parent, value)
|
def associate_casted_value_to_parent(parent, value)
|
||||||
value.casted_by = parent if value.respond_to?(:casted_by)
|
value.casted_by = parent if value.respond_to?(:casted_by)
|
||||||
value.casted_by_property = self if value.respond_to?(:casted_by_property)
|
value.casted_by_property = self if value.respond_to?(:casted_by_property)
|
||||||
|
|
|
@ -73,12 +73,12 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# Base
|
# Base
|
||||||
def new(*args)
|
def new(attrs = {}, options = {}, &block)
|
||||||
proxy_update(model.new(*args))
|
proxy_block_update(:new, attrs, options, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_from_database(doc = {})
|
def build_from_database(attrs = {}, options = {}, &block)
|
||||||
proxy_update(model.build_from_database(doc))
|
proxy_block_update(:build_from_database, attrs, options, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def method_missing(m, *args, &block)
|
def method_missing(m, *args, &block)
|
||||||
|
@ -170,6 +170,13 @@ module CouchRest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def proxy_block_update(method, *args, &block)
|
||||||
|
model.send(method, *args) do |doc|
|
||||||
|
proxy_update(doc)
|
||||||
|
yield doc if block_given?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,7 @@ CouchRest::Design.class_eval do
|
||||||
flatten =
|
flatten =
|
||||||
lambda {|r|
|
lambda {|r|
|
||||||
(recurse = lambda {|v|
|
(recurse = lambda {|v|
|
||||||
if v.is_a?(Hash)
|
if v.is_a?(Hash) || v.is_a?(CouchRest::Document)
|
||||||
v.to_a.map{|v| recurse.call(v)}.flatten
|
v.to_a.map{|v| recurse.call(v)}.flatten
|
||||||
elsif v.is_a?(Array)
|
elsif v.is_a?(Array)
|
||||||
v.flatten.map{|v| recurse.call(v)}
|
v.flatten.map{|v| recurse.call(v)}
|
||||||
|
|
|
@ -13,18 +13,29 @@ module CouchRest
|
||||||
# Validations may be applied to both Model::Base and Model::CastedModel
|
# Validations may be applied to both Model::Base and Model::CastedModel
|
||||||
module Validations
|
module Validations
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
included do
|
|
||||||
include ActiveModel::Validations
|
include ActiveModel::Validations
|
||||||
include ActiveModel::Validations::Callbacks
|
|
||||||
end
|
|
||||||
|
|
||||||
|
# Determine if the document is valid.
|
||||||
|
#
|
||||||
|
# @example Is the document valid?
|
||||||
|
# person.valid?
|
||||||
|
#
|
||||||
|
# @example Is the document valid in a context?
|
||||||
|
# person.valid?(:create)
|
||||||
|
#
|
||||||
|
# @param [ Symbol ] context The optional validation context.
|
||||||
|
#
|
||||||
|
# @return [ true, false ] True if valid, false if not.
|
||||||
|
#
|
||||||
|
def valid?(context = nil)
|
||||||
|
super context ? context : (new? ? :create : :update)
|
||||||
|
end
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
|
|
||||||
# Validates the associated casted model. This method should not be
|
# Validates the associated casted model. This method should not be
|
||||||
# used within your code as it is automatically included when a CastedModel
|
# used within your code as it is automatically included when a CastedModel
|
||||||
# is used inside the model.
|
# is used inside the model.
|
||||||
#
|
|
||||||
def validates_casted_model(*args)
|
def validates_casted_model(*args)
|
||||||
validates_with(CastedModelValidator, _merge_attributes(args))
|
validates_with(CastedModelValidator, _merge_attributes(args))
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,8 +60,8 @@ require "couchrest/model/core_extensions/time_parsing"
|
||||||
# Base libraries
|
# Base libraries
|
||||||
require "couchrest/model/casted_model"
|
require "couchrest/model/casted_model"
|
||||||
require "couchrest/model/base"
|
require "couchrest/model/base"
|
||||||
# Add rails support *after* everything has loaded
|
|
||||||
|
|
||||||
|
# Add rails support *after* everything has loaded
|
||||||
if defined?(Rails)
|
if defined?(Rails)
|
||||||
require "couchrest/railtie"
|
require "couchrest/railtie"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
|
||||||
|
|
||||||
begin
|
|
||||||
require 'rubygems' unless ENV['SKIP_RUBYGEMS']
|
|
||||||
require 'active_support/json'
|
|
||||||
ActiveSupport::JSON.backend = :JSONGem
|
|
||||||
|
|
||||||
class PlainParent
|
|
||||||
class_inheritable_accessor :foo
|
|
||||||
self.foo = :bar
|
|
||||||
end
|
|
||||||
|
|
||||||
class PlainChild < PlainParent
|
|
||||||
end
|
|
||||||
|
|
||||||
class ExtendedParent < CouchRest::Model::Base
|
|
||||||
class_inheritable_accessor :foo
|
|
||||||
self.foo = :bar
|
|
||||||
end
|
|
||||||
|
|
||||||
class ExtendedChild < ExtendedParent
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Using chained inheritance without CouchRest::Model::Base" do
|
|
||||||
it "should preserve inheritable attributes" do
|
|
||||||
PlainParent.foo.should == :bar
|
|
||||||
PlainChild.foo.should == :bar
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "Using chained inheritance with CouchRest::Model::Base" do
|
|
||||||
it "should preserve inheritable attributes" do
|
|
||||||
ExtendedParent.foo.should == :bar
|
|
||||||
ExtendedChild.foo.should == :bar
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue LoadError
|
|
||||||
puts "This spec requires 'active_support/json' to be loaded"
|
|
||||||
end
|
|
|
@ -22,6 +22,7 @@ class Article < CouchRest::Model::Base
|
||||||
|
|
||||||
property :date, Date
|
property :date, Date
|
||||||
property :slug, :read_only => true
|
property :slug, :read_only => true
|
||||||
|
property :user_id
|
||||||
property :title
|
property :title
|
||||||
property :tags, [String]
|
property :tags, [String]
|
||||||
|
|
|
@ -83,11 +83,23 @@ class WithCallBacks < CouchRest::Model::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Following two fixture classes have __intentionally__ diffent syntax for setting the validation context
|
||||||
|
class WithContextualValidationOnCreate < CouchRest::Model::Base
|
||||||
|
property(:name, String)
|
||||||
|
validates(:name, :presence => {:on => :create})
|
||||||
|
end
|
||||||
|
|
||||||
|
class WithContextualValidationOnUpdate < CouchRest::Model::Base
|
||||||
|
property(:name, String)
|
||||||
|
validates(:name, :presence => true, :on => :update)
|
||||||
|
end
|
||||||
|
|
||||||
class WithTemplateAndUniqueID < CouchRest::Model::Base
|
class WithTemplateAndUniqueID < CouchRest::Model::Base
|
||||||
use_database TEST_SERVER.default_database
|
use_database TEST_SERVER.default_database
|
||||||
unique_id do |model|
|
unique_id do |model|
|
||||||
model['important-field']
|
model.slug
|
||||||
end
|
end
|
||||||
|
property :slug
|
||||||
property :preset, :default => 'value'
|
property :preset, :default => 'value'
|
||||||
property :has_no_default
|
property :has_no_default
|
||||||
end
|
end
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'person'
|
||||||
|
|
||||||
class Card < CouchRest::Model::Base
|
class Card < CouchRest::Model::Base
|
||||||
# Set the default database to use
|
# Set the default database to use
|
||||||
use_database DB
|
use_database DB
|
|
@ -17,3 +17,7 @@ class Cat < CouchRest::Model::Base
|
||||||
property :number
|
property :number
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class ChildCat < Cat
|
||||||
|
property :mother, Cat
|
||||||
|
property :siblings, [Cat]
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
require File.join(FIXTURE_PATH, 'more', 'question')
|
require 'question'
|
||||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
require 'person'
|
||||||
|
|
||||||
class Course < CouchRest::Model::Base
|
class Course < CouchRest::Model::Base
|
||||||
use_database TEST_SERVER.default_database
|
use_database TEST_SERVER.default_database
|
5
spec/fixtures/models/key_chain.rb
vendored
Normal file
5
spec/fixtures/models/key_chain.rb
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class KeyChain < CouchRest::Model::Base
|
||||||
|
use_database(DB)
|
||||||
|
|
||||||
|
property(:keys, Hash)
|
||||||
|
end
|
4
spec/fixtures/models/membership.rb
vendored
Normal file
4
spec/fixtures/models/membership.rb
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
class Membership < Hash
|
||||||
|
include CouchRest::Model::CastedModel
|
||||||
|
|
||||||
|
end
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'cat'
|
||||||
|
|
||||||
class Person < Hash
|
class Person < Hash
|
||||||
include ::CouchRest::Model::CastedModel
|
include ::CouchRest::Model::CastedModel
|
||||||
property :pet, Cat
|
property :pet, Cat
|
6
spec/fixtures/models/project.rb
vendored
Normal file
6
spec/fixtures/models/project.rb
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class Project < CouchRest::Model::Base
|
||||||
|
use_database DB
|
||||||
|
property :name, String
|
||||||
|
timestamps!
|
||||||
|
view_by :name
|
||||||
|
end
|
|
@ -1,5 +1,6 @@
|
||||||
require File.join(FIXTURE_PATH, 'more', 'client')
|
require 'client'
|
||||||
require File.join(FIXTURE_PATH, 'more', 'sale_entry')
|
require 'sale_entry'
|
||||||
|
|
||||||
class SaleInvoice < CouchRest::Model::Base
|
class SaleInvoice < CouchRest::Model::Base
|
||||||
use_database DB
|
use_database DB
|
||||||
|
|
8
spec/functional/validations_spec.rb
Normal file
8
spec/functional/validations_spec.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
require File.expand_path('../../spec_helper', __FILE__)
|
||||||
|
|
||||||
|
describe CouchRest::Model::Validations do
|
||||||
|
|
||||||
|
let(:invoice) do
|
||||||
|
Invoice.new()
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,11 +1,16 @@
|
||||||
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
||||||
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
||||||
|
|
||||||
require "bundler/setup"
|
require "bundler/setup"
|
||||||
require "rubygems"
|
require "rubygems"
|
||||||
require "rspec" # Satisfies Autotest and anyone else not using the Rake tasks
|
require "rspec"
|
||||||
|
|
||||||
require File.join(File.dirname(__FILE__), '..','lib','couchrest_model')
|
require 'couchrest_model'
|
||||||
# check the following file to see how to use the spec'd features.
|
|
||||||
|
|
||||||
unless defined?(FIXTURE_PATH)
|
unless defined?(FIXTURE_PATH)
|
||||||
|
MODEL_PATH = File.join(File.dirname(__FILE__), "fixtures", "models")
|
||||||
|
$LOAD_PATH.unshift(MODEL_PATH)
|
||||||
|
|
||||||
FIXTURE_PATH = File.join(File.dirname(__FILE__), '/fixtures')
|
FIXTURE_PATH = File.join(File.dirname(__FILE__), '/fixtures')
|
||||||
SCRATCH_PATH = File.join(File.dirname(__FILE__), '/tmp')
|
SCRATCH_PATH = File.join(File.dirname(__FILE__), '/tmp')
|
||||||
|
|
||||||
|
@ -16,17 +21,6 @@ unless defined?(FIXTURE_PATH)
|
||||||
DB = TEST_SERVER.database(TESTDB)
|
DB = TEST_SERVER.database(TESTDB)
|
||||||
end
|
end
|
||||||
|
|
||||||
class Basic < CouchRest::Model::Base
|
|
||||||
use_database TEST_SERVER.default_database
|
|
||||||
end
|
|
||||||
|
|
||||||
def reset_test_db!
|
|
||||||
DB.recreate! rescue nil
|
|
||||||
# Reset the Design Cache
|
|
||||||
Thread.current[:couchrest_design_cache] = {}
|
|
||||||
DB
|
|
||||||
end
|
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.before(:all) { reset_test_db! }
|
config.before(:all) { reset_test_db! }
|
||||||
|
|
||||||
|
@ -39,6 +33,21 @@ RSpec.configure do |config|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Require each of the fixture models
|
||||||
|
Dir[ File.join(MODEL_PATH, "*.rb") ].sort.each { |file| require File.basename(file) }
|
||||||
|
|
||||||
|
class Basic < CouchRest::Model::Base
|
||||||
|
use_database TEST_SERVER.default_database
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_test_db!
|
||||||
|
DB.recreate! rescue nil
|
||||||
|
# Reset the Design Cache
|
||||||
|
Thread.current[:couchrest_design_cache] = {}
|
||||||
|
DB
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def couchdb_lucene_available?
|
def couchdb_lucene_available?
|
||||||
lucene_path = "http://localhost:5985/"
|
lucene_path = "http://localhost:5985/"
|
||||||
url = URI.parse(lucene_path)
|
url = URI.parse(lucene_path)
|
||||||
|
|
30
spec/unit/active_model_lint_spec.rb
Normal file
30
spec/unit/active_model_lint_spec.rb
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'test/unit/assertions'
|
||||||
|
require 'active_model/lint'
|
||||||
|
|
||||||
|
class CompliantModel < CouchRest::Model::Base
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe CouchRest::Model::Base do
|
||||||
|
include Test::Unit::Assertions
|
||||||
|
include ActiveModel::Lint::Tests
|
||||||
|
|
||||||
|
before :each do
|
||||||
|
@model = CompliantModel.new
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "active model lint tests" do
|
||||||
|
ActiveModel::Lint::Tests.public_instance_methods.map{|m| m.to_s}.grep(/^test/).each do |m|
|
||||||
|
example m.gsub('_',' ') do
|
||||||
|
send m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def model
|
||||||
|
@model
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,7 +1,5 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
require 'spec_helper'
|
||||||
require File.join(FIXTURE_PATH, 'more', 'sale_invoice')
|
|
||||||
|
|
||||||
|
|
||||||
describe "Assocations" do
|
describe "Assocations" do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
require 'spec_helper'
|
||||||
|
|
||||||
describe "Model attachments" do
|
describe "Model attachments" do
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
require "spec_helper"
|
||||||
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
|
describe "Model Base" do
|
||||||
|
|
||||||
|
@ -49,6 +43,32 @@ describe "Model Base" do
|
||||||
@obj.database.should eql('database')
|
@obj.database.should eql('database')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should only set defined properties" do
|
||||||
|
@doc = WithDefaultValues.new(:name => 'test', :foo => 'bar')
|
||||||
|
@doc['name'].should eql('test')
|
||||||
|
@doc['foo'].should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should set all properties with :directly_set_attributes option" do
|
||||||
|
@doc = WithDefaultValues.new({:name => 'test', :foo => 'bar'}, :directly_set_attributes => true)
|
||||||
|
@doc['name'].should eql('test')
|
||||||
|
@doc['foo'].should eql('bar')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should set the model type" do
|
||||||
|
@doc = WithDefaultValues.new()
|
||||||
|
@doc[WithDefaultValues.model_type_key].should eql('WithDefaultValues')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should call after_initialize method if available" do
|
||||||
|
@doc = WithAfterInitializeMethod.new
|
||||||
|
@doc['some_value'].should eql('value')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should call after_initialize after block" do
|
||||||
|
@doc = WithAfterInitializeMethod.new {|d| d.some_value = "foo"}
|
||||||
|
@doc['some_value'].should eql('foo')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "ActiveModel compatability Basic" do
|
describe "ActiveModel compatability Basic" do
|
||||||
|
@ -90,14 +110,22 @@ describe "Model Base" do
|
||||||
describe "#persisted?" do
|
describe "#persisted?" do
|
||||||
context "when the document is new" do
|
context "when the document is new" do
|
||||||
it "returns false" do
|
it "returns false" do
|
||||||
@obj.persisted?.should == false
|
@obj.persisted?.should be_false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the document is not new" do
|
context "when the document is not new" do
|
||||||
it "returns id" do
|
it "returns id" do
|
||||||
@obj.save
|
@obj.save
|
||||||
@obj.persisted?.should == true
|
@obj.persisted?.should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the document is destroyed" do
|
||||||
|
it "returns false" do
|
||||||
|
@obj.save
|
||||||
|
@obj.destroy
|
||||||
|
@obj.persisted?.should be_false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -109,7 +137,38 @@ describe "Model Base" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#destroyed?" do
|
||||||
|
it "should be present" do
|
||||||
|
@obj.should respond_to(:destroyed?)
|
||||||
|
end
|
||||||
|
it "should return false with new object" do
|
||||||
|
@obj.destroyed?.should be_false
|
||||||
|
end
|
||||||
|
it "should return true after destroy" do
|
||||||
|
@obj.save
|
||||||
|
@obj.destroy
|
||||||
|
@obj.destroyed?.should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "comparisons" do
|
||||||
|
describe "#==" do
|
||||||
|
it "should be true on same document" do
|
||||||
|
p = Project.create
|
||||||
|
p.should eql(p)
|
||||||
|
end
|
||||||
|
it "should be true after loading" do
|
||||||
|
p = Project.create
|
||||||
|
p.should eql(Project.get(p.id))
|
||||||
|
end
|
||||||
|
it "should not be true if databases do not match" do
|
||||||
|
p = Project.create
|
||||||
|
p2 = p.dup
|
||||||
|
p2.stub!(:database).and_return('other')
|
||||||
|
p.should_not eql(p2)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "update attributes without saving" do
|
describe "update attributes without saving" do
|
||||||
|
@ -232,7 +291,7 @@ describe "Model Base" do
|
||||||
WithTemplateAndUniqueID.all.map{|o| o.destroy}
|
WithTemplateAndUniqueID.all.map{|o| o.destroy}
|
||||||
WithTemplateAndUniqueID.database.bulk_delete
|
WithTemplateAndUniqueID.database.bulk_delete
|
||||||
@tmpl = WithTemplateAndUniqueID.new
|
@tmpl = WithTemplateAndUniqueID.new
|
||||||
@tmpl2 = WithTemplateAndUniqueID.new(:preset => 'not_value', 'important-field' => '1')
|
@tmpl2 = WithTemplateAndUniqueID.new(:preset => 'not_value', 'slug' => '1')
|
||||||
end
|
end
|
||||||
it "should have fields set when new" do
|
it "should have fields set when new" do
|
||||||
@tmpl.preset.should == 'value'
|
@tmpl.preset.should == 'value'
|
||||||
|
@ -253,10 +312,10 @@ describe "Model Base" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
WithTemplateAndUniqueID.all.map{|o| o.destroy}
|
WithTemplateAndUniqueID.all.map{|o| o.destroy}
|
||||||
WithTemplateAndUniqueID.database.bulk_delete
|
WithTemplateAndUniqueID.database.bulk_delete
|
||||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
WithTemplateAndUniqueID.new('slug' => '1').save
|
||||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
WithTemplateAndUniqueID.new('slug' => '2').save
|
||||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
WithTemplateAndUniqueID.new('slug' => '3').save
|
||||||
WithTemplateAndUniqueID.new('important-field' => '4').save
|
WithTemplateAndUniqueID.new('slug' => '4').save
|
||||||
end
|
end
|
||||||
it "should find all" do
|
it "should find all" do
|
||||||
rs = WithTemplateAndUniqueID.all
|
rs = WithTemplateAndUniqueID.all
|
||||||
|
@ -274,9 +333,9 @@ describe "Model Base" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it ".count should return the number of documents" do
|
it ".count should return the number of documents" do
|
||||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
WithTemplateAndUniqueID.new('slug' => '1').save
|
||||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
WithTemplateAndUniqueID.new('slug' => '2').save
|
||||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
WithTemplateAndUniqueID.new('slug' => '3').save
|
||||||
|
|
||||||
WithTemplateAndUniqueID.count.should == 3
|
WithTemplateAndUniqueID.count.should == 3
|
||||||
end
|
end
|
||||||
|
@ -285,14 +344,14 @@ describe "Model Base" do
|
||||||
describe "finding the first instance of a model" do
|
describe "finding the first instance of a model" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
WithTemplateAndUniqueID.new('slug' => '1').save
|
||||||
WithTemplateAndUniqueID.new('important-field' => '2').save
|
WithTemplateAndUniqueID.new('slug' => '2').save
|
||||||
WithTemplateAndUniqueID.new('important-field' => '3').save
|
WithTemplateAndUniqueID.new('slug' => '3').save
|
||||||
WithTemplateAndUniqueID.new('important-field' => '4').save
|
WithTemplateAndUniqueID.new('slug' => '4').save
|
||||||
end
|
end
|
||||||
it "should find first" do
|
it "should find first" do
|
||||||
rs = WithTemplateAndUniqueID.first
|
rs = WithTemplateAndUniqueID.first
|
||||||
rs['important-field'].should == "1"
|
rs['slug'].should == "1"
|
||||||
end
|
end
|
||||||
it "should return nil if no instances are found" do
|
it "should return nil if no instances are found" do
|
||||||
WithTemplateAndUniqueID.all.each {|obj| obj.destroy }
|
WithTemplateAndUniqueID.all.each {|obj| obj.destroy }
|
||||||
|
@ -370,13 +429,6 @@ describe "Model Base" do
|
||||||
end
|
end
|
||||||
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
|
describe "recursive validation on a model" do
|
||||||
before :each do
|
before :each do
|
||||||
reset_test_db!
|
reset_test_db!
|
|
@ -1,12 +1,5 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
require "spec_helper"
|
||||||
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', 'question')
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
|
||||||
|
|
||||||
|
|
||||||
class WithCastedModelMixin < Hash
|
class WithCastedModelMixin < Hash
|
||||||
include CouchRest::Model::CastedModel
|
include CouchRest::Model::CastedModel
|
|
@ -1,7 +1,4 @@
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
require "spec_helper"
|
||||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
|
||||||
|
|
||||||
class Driver < CouchRest::Model::Base
|
class Driver < CouchRest::Model::Base
|
||||||
use_database TEST_SERVER.default_database
|
use_database TEST_SERVER.default_database
|
|
@ -1,4 +1,4 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
|
|
||||||
class UnattachedDoc < CouchRest::Model::Base
|
class UnattachedDoc < CouchRest::Model::Base
|
||||||
# Note: no use_database here
|
# Note: no use_database here
|
||||||
|
@ -123,6 +123,35 @@ describe "Proxy Class" do
|
||||||
u.respond_to?(:database).should be_false
|
u.respond_to?(:database).should be_false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#get!" do
|
||||||
|
it "raises exception when passed a nil" do
|
||||||
|
expect { @us.get!(nil)}.to raise_error(CouchRest::Model::DocumentNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises exception when passed an empty string " do
|
||||||
|
expect { @us.get!("")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises exception when document with provided id does not exist" do
|
||||||
|
expect { @us.get!("thisisnotreallyadocumentid")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#find!" do
|
||||||
|
it "raises exception when passed a nil" do
|
||||||
|
expect { @us.find!(nil)}.to raise_error(CouchRest::Model::DocumentNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises exception when passed an empty string " do
|
||||||
|
expect { @us.find!("")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises exception when document with provided id does not exist" do
|
||||||
|
expect { @us.find!("thisisnotreallyadocumentid")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Sam Lown 2010-04-07
|
# Sam Lown 2010-04-07
|
||||||
# Removed as unclear why this should happen as before my changes
|
# Removed as unclear why this should happen as before my changes
|
||||||
# this happend by accident, not explicitly.
|
# this happend by accident, not explicitly.
|
|
@ -1,5 +1,4 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
|
||||||
|
|
||||||
describe "Collections" do
|
describe "Collections" do
|
||||||
|
|
||||||
|
@ -27,21 +26,20 @@ describe "Collections" do
|
||||||
end
|
end
|
||||||
it "should provide a class method for paginate" do
|
it "should provide a class method for paginate" do
|
||||||
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
||||||
:per_page => 3, :descending => true, :key => Date.today, :include_docs => true)
|
:per_page => 3, :descending => true, :key => Date.today)
|
||||||
articles.size.should == 3
|
articles.size.should == 3
|
||||||
|
|
||||||
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
||||||
:per_page => 3, :page => 2, :descending => true, :key => Date.today, :include_docs => true)
|
:per_page => 3, :page => 2, :descending => true, :key => Date.today)
|
||||||
articles.size.should == 3
|
articles.size.should == 3
|
||||||
|
|
||||||
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
||||||
:per_page => 3, :page => 3, :descending => true, :key => Date.today, :include_docs => true)
|
:per_page => 3, :page => 3, :descending => true, :key => Date.today)
|
||||||
articles.size.should == 1
|
articles.size.should == 1
|
||||||
end
|
end
|
||||||
it "should provide a class method for paginated_each" do
|
it "should provide a class method for paginated_each" do
|
||||||
options = { :design_doc => 'Article', :view_name => 'by_date',
|
options = { :design_doc => 'Article', :view_name => 'by_date',
|
||||||
:per_page => 3, :page => 1, :descending => true, :key => Date.today,
|
:per_page => 3, :page => 1, :descending => true, :key => Date.today }
|
||||||
:include_docs => true }
|
|
||||||
Article.paginated_each(options) do |a|
|
Article.paginated_each(options) do |a|
|
||||||
a.should_not be_nil
|
a.should_not be_nil
|
||||||
end
|
end
|
|
@ -1,8 +1,7 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
require "spec_helper"
|
||||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
|
||||||
|
|
||||||
describe CouchRest::Model::Base do
|
describe CouchRest::Model::Configuration do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@class = Class.new(CouchRest::Model::Base)
|
@class = Class.new(CouchRest::Model::Base)
|
|
@ -1,7 +1,7 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
require 'spec_helper'
|
||||||
|
|
||||||
describe CouchRest::Model::Base do
|
describe CouchRest::Model::Connection do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@class = Class.new(CouchRest::Model::Base)
|
@class = Class.new(CouchRest::Model::Base)
|
|
@ -1,10 +1,7 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
describe CouchRest::Model::DesignDoc do
|
||||||
require File.join(FIXTURE_PATH, 'base')
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
|
||||||
|
|
||||||
describe "Design Documents" do
|
|
||||||
|
|
||||||
before :all do
|
before :all do
|
||||||
reset_test_db!
|
reset_test_db!
|
||||||
|
@ -202,7 +199,7 @@ describe "Design Documents" do
|
||||||
describe "lazily refreshing the design document" do
|
describe "lazily refreshing the design document" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
WithTemplateAndUniqueID.new('important-field' => '1').save
|
WithTemplateAndUniqueID.new('slug' => '1').save
|
||||||
end
|
end
|
||||||
it "should not save the design doc twice" do
|
it "should not save the design doc twice" do
|
||||||
WithTemplateAndUniqueID.all
|
WithTemplateAndUniqueID.all
|
|
@ -1,10 +1,9 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
|
|
||||||
class DesignModel < CouchRest::Model::Base
|
class DesignModel < CouchRest::Model::Base
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Design" do
|
describe CouchRest::Model::Designs do
|
||||||
|
|
||||||
it "should accessable from model" do
|
it "should accessable from model" do
|
||||||
DesignModel.respond_to?(:design).should be_true
|
DesignModel.respond_to?(:design).should be_true
|
|
@ -1,10 +1,4 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
|
|
||||||
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')
|
|
||||||
|
|
||||||
class WithCastedModelMixin < Hash
|
class WithCastedModelMixin < Hash
|
||||||
include CouchRest::Model::CastedModel
|
include CouchRest::Model::CastedModel
|
||||||
|
@ -241,6 +235,14 @@ describe "Dirty" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should report changes if an array is popped after reload" do
|
||||||
|
should_change_array do |array, obj|
|
||||||
|
obj.reload
|
||||||
|
obj.keywords.pop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
it "should report no changes if an empty array is popped" do
|
it "should report no changes if an empty array is popped" do
|
||||||
should_not_change_array do |array, obj|
|
should_not_change_array do |array, obj|
|
||||||
array.clear
|
array.clear
|
||||||
|
@ -249,6 +251,50 @@ describe "Dirty" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should report changes on deletion from an array" do
|
||||||
|
should_change_array do |array, obj|
|
||||||
|
array << "keyword"
|
||||||
|
obj.save!
|
||||||
|
array.delete_at(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
should_change_array do |array, obj|
|
||||||
|
array << "keyword"
|
||||||
|
obj.save!
|
||||||
|
array.delete("keyword")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should report changes on deletion from an array after reload" do
|
||||||
|
should_change_array do |array, obj|
|
||||||
|
array << "keyword"
|
||||||
|
obj.save!
|
||||||
|
obj.reload
|
||||||
|
array.delete_at(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
should_change_array do |array, obj|
|
||||||
|
array << "keyword"
|
||||||
|
obj.save!
|
||||||
|
obj.reload
|
||||||
|
array.delete("keyword")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should report no changes on deletion from an empty array" do
|
||||||
|
should_not_change_array do |array, obj|
|
||||||
|
array.clear
|
||||||
|
obj.save!
|
||||||
|
array.delete_at(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
should_not_change_array do |array, obj|
|
||||||
|
array.clear
|
||||||
|
obj.save!
|
||||||
|
array.delete("keyword")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "should report changes if an array is pushed" do
|
it "should report changes if an array is pushed" do
|
||||||
should_change_array do |array, obj|
|
should_change_array do |array, obj|
|
||||||
array.push("keyword")
|
array.push("keyword")
|
33
spec/unit/inherited_spec.rb
Normal file
33
spec/unit/inherited_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
class PlainParent
|
||||||
|
class_inheritable_accessor :foo
|
||||||
|
self.foo = :bar
|
||||||
|
end
|
||||||
|
|
||||||
|
class PlainChild < PlainParent
|
||||||
|
end
|
||||||
|
|
||||||
|
class ExtendedParent < CouchRest::Model::Base
|
||||||
|
class_inheritable_accessor :foo
|
||||||
|
self.foo = :bar
|
||||||
|
end
|
||||||
|
|
||||||
|
class ExtendedChild < ExtendedParent
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Using chained inheritance without CouchRest::Model::Base" do
|
||||||
|
it "should preserve inheritable attributes" do
|
||||||
|
PlainParent.foo.should == :bar
|
||||||
|
PlainChild.foo.should == :bar
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Using chained inheritance with CouchRest::Model::Base" do
|
||||||
|
it "should preserve inheritable attributes" do
|
||||||
|
ExtendedParent.foo.should == :bar
|
||||||
|
ExtendedChild.foo.should == :bar
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
require 'spec_helper'
|
||||||
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
|
describe CouchRest::Model::Persistence do
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@obj = WithDefaultValues.new
|
@obj = WithDefaultValues.new
|
||||||
|
@ -34,8 +29,8 @@ describe "Model Persistence" do
|
||||||
describe "basic saving and retrieving" do
|
describe "basic saving and retrieving" do
|
||||||
it "should work fine" do
|
it "should work fine" do
|
||||||
@obj.name = "should be easily saved and retrieved"
|
@obj.name = "should be easily saved and retrieved"
|
||||||
@obj.save
|
@obj.save!
|
||||||
saved_obj = WithDefaultValues.get(@obj.id)
|
saved_obj = WithDefaultValues.get!(@obj.id)
|
||||||
saved_obj.should_not be_nil
|
saved_obj.should_not be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -81,6 +76,18 @@ describe "Model Persistence" do
|
||||||
article.should_not be_new
|
article.should_not be_new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "yields new instance to block before saving (#create)" do
|
||||||
|
article = Article.create{|a| a.title = 'my create init block test'}
|
||||||
|
article.title.should == 'my create init block test'
|
||||||
|
article.should_not be_new
|
||||||
|
end
|
||||||
|
|
||||||
|
it "yields new instance to block before saving (#create!)" do
|
||||||
|
article = Article.create{|a| a.title = 'my create bang init block test'}
|
||||||
|
article.title.should == 'my create bang init block test'
|
||||||
|
article.should_not be_new
|
||||||
|
end
|
||||||
|
|
||||||
it "should trigger the create callbacks" do
|
it "should trigger the create callbacks" do
|
||||||
doc = WithCallBacks.create(:name => 'my other test')
|
doc = WithCallBacks.create(:name => 'my other test')
|
||||||
doc.run_before_create.should be_true
|
doc.run_before_create.should be_true
|
||||||
|
@ -210,34 +217,34 @@ describe "Model Persistence" do
|
||||||
|
|
||||||
it "should require the field" do
|
it "should require the field" do
|
||||||
lambda{@templated.save}.should raise_error
|
lambda{@templated.save}.should raise_error
|
||||||
@templated['important-field'] = 'very-important'
|
@templated['slug'] = 'very-important'
|
||||||
@templated.save.should be_true
|
@templated.save.should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should save with the id" do
|
it "should save with the id" do
|
||||||
@templated['important-field'] = 'very-important'
|
@templated['slug'] = 'very-important'
|
||||||
@templated.save.should be_true
|
@templated.save.should be_true
|
||||||
t = WithTemplateAndUniqueID.get('very-important')
|
t = WithTemplateAndUniqueID.get('very-important')
|
||||||
t.should == @templated
|
t.should == @templated
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not change the id on update" do
|
it "should not change the id on update" do
|
||||||
@templated['important-field'] = 'very-important'
|
@templated['slug'] = 'very-important'
|
||||||
@templated.save.should be_true
|
@templated.save.should be_true
|
||||||
@templated['important-field'] = 'not-important'
|
@templated['slug'] = 'not-important'
|
||||||
@templated.save.should be_true
|
@templated.save.should be_true
|
||||||
t = WithTemplateAndUniqueID.get('very-important')
|
t = WithTemplateAndUniqueID.get('very-important')
|
||||||
t.id.should == @templated.id
|
t.id.should == @templated.id
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should raise an error when the id is taken" do
|
it "should raise an error when the id is taken" do
|
||||||
@templated['important-field'] = 'very-important'
|
@templated['slug'] = 'very-important'
|
||||||
@templated.save.should be_true
|
@templated.save.should be_true
|
||||||
lambda{WithTemplateAndUniqueID.new('important-field' => 'very-important').save}.should raise_error
|
lambda{WithTemplateAndUniqueID.new('slug' => 'very-important').save}.should raise_error
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should set the id" do
|
it "should set the id" do
|
||||||
@templated['important-field'] = 'very-important'
|
@templated['slug'] = 'very-important'
|
||||||
@templated.save.should be_true
|
@templated.save.should be_true
|
||||||
@templated.id.should == 'very-important'
|
@templated.id.should == 'very-important'
|
||||||
end
|
end
|
||||||
|
@ -245,22 +252,31 @@ describe "Model Persistence" do
|
||||||
|
|
||||||
describe "destroying an instance" do
|
describe "destroying an instance" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@dobj = Basic.new
|
@dobj = Event.new
|
||||||
@dobj.save.should be_true
|
@dobj.save.should be_true
|
||||||
end
|
end
|
||||||
it "should return true" do
|
it "should return true" do
|
||||||
result = @dobj.destroy
|
result = @dobj.destroy
|
||||||
result.should be_true
|
result.should be_true
|
||||||
end
|
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
|
it "should make it go away" do
|
||||||
@dobj.destroy
|
@dobj.destroy
|
||||||
lambda{Basic.get!(@dobj.id)}.should raise_error
|
lambda{Basic.get!(@dobj.id)}.should raise_error(CouchRest::Model::DocumentNotFound)
|
||||||
|
end
|
||||||
|
it "should freeze the object" do
|
||||||
|
@dobj.destroy
|
||||||
|
# In Ruby 1.9.2 this raises RuntimeError, in 1.8.7 TypeError, D'OH!
|
||||||
|
lambda { @dobj.subject = "Test" }.should raise_error(StandardError)
|
||||||
|
end
|
||||||
|
it "trying to save after should fail" do
|
||||||
|
@dobj.destroy
|
||||||
|
lambda { @dobj.save }.should raise_error(StandardError)
|
||||||
|
lambda{Basic.get!(@dobj.id)}.should raise_error(CouchRest::Model::DocumentNotFound)
|
||||||
|
end
|
||||||
|
it "should make destroyed? true" do
|
||||||
|
@dobj.destroyed?.should be_false
|
||||||
|
@dobj.destroy
|
||||||
|
@dobj.destroyed?.should be_true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -340,6 +356,27 @@ describe "Model Persistence" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "with contextual validation on ”create”" do
|
||||||
|
it "should validate only within ”create” context" do
|
||||||
|
doc = WithContextualValidationOnCreate.new
|
||||||
|
doc.save.should be_false
|
||||||
|
doc.name = "Alice"
|
||||||
|
doc.save.should be_true
|
||||||
|
|
||||||
|
doc.update_attributes(:name => nil).should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with contextual validation on ”update”" do
|
||||||
|
it "should validate only within ”update” context" do
|
||||||
|
doc = WithContextualValidationOnUpdate.new
|
||||||
|
doc.save.should be_true
|
||||||
|
|
||||||
|
doc.update_attributes(:name => nil).should be_false
|
||||||
|
doc.update_attributes(:name => "Bob").should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "save" do
|
describe "save" do
|
||||||
it "should run the after filter after saving" do
|
it "should run the after filter after saving" do
|
||||||
@doc.run_after_save.should be_nil
|
@doc.run_after_save.should be_nil
|
|
@ -1,4 +1,4 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
|
|
||||||
describe "Model Attributes" do
|
describe "Model Attributes" do
|
||||||
|
|
|
@ -1,17 +1,7 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
require 'spec_helper'
|
||||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
|
||||||
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', 'user')
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
|
||||||
|
|
||||||
|
describe CouchRest::Model::Property do
|
||||||
describe "Model properties" do
|
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
reset_test_db!
|
reset_test_db!
|
||||||
|
@ -239,6 +229,16 @@ describe "Model properties" do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "properties of hash of casted models" do
|
||||||
|
it "should be able to assign a casted hash to a hash property" do
|
||||||
|
chain = KeyChain.new
|
||||||
|
keys = {"House" => "8==$", "Office" => "<>==U"}
|
||||||
|
chain.keys = keys
|
||||||
|
chain.keys = chain.keys
|
||||||
|
chain.keys.should == keys
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "properties of array of casted models" do
|
describe "properties of array of casted models" do
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
|
@ -265,9 +265,9 @@ describe "properties of array of casted models" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should allow attribute to be set from hash with ordered keys and sub-hashes" do
|
it "should allow attribute to be set from hash with ordered keys and sub-hashes" do
|
||||||
@course.questions = { '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} }
|
@course.questions = { '10' => {:q => 'Test10'}, '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} }
|
||||||
@course.questions.length.should eql(2)
|
@course.questions.length.should eql(3)
|
||||||
@course.questions.last.q.should eql('Test2')
|
@course.questions.last.q.should eql('Test10')
|
||||||
@course.questions.last.class.should eql(Question)
|
@course.questions.last.class.should eql(Question)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ describe "properties of array of casted models" do
|
||||||
it "should raise an error if attempting to set single value for array type" do
|
it "should raise an error if attempting to set single value for array type" do
|
||||||
lambda {
|
lambda {
|
||||||
@course.questions = Question.new(:q => 'test1')
|
@course.questions = Question.new(:q => 'test1')
|
||||||
}.should raise_error
|
}.should raise_error(/Expecting an array/)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -315,6 +315,28 @@ describe "a casted model retrieved from the database" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "nested models (not casted)" do
|
||||||
|
before(:each) do
|
||||||
|
reset_test_db!
|
||||||
|
@cat = ChildCat.new(:name => 'Stimpy')
|
||||||
|
@cat.mother = {:name => 'Stinky'}
|
||||||
|
@cat.siblings = [{:name => 'Feather'}, {:name => 'Felix'}]
|
||||||
|
@cat.save
|
||||||
|
@cat = ChildCat.get(@cat.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should correctly save single relation" do
|
||||||
|
@cat.mother.name.should eql('Stinky')
|
||||||
|
@cat.mother.casted_by.should eql(@cat)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should correctly save collection" do
|
||||||
|
@cat.siblings.first.name.should eql("Feather")
|
||||||
|
@cat.siblings.last.casted_by.should eql(@cat)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
describe "Property Class" do
|
describe "Property Class" do
|
||||||
|
|
||||||
it "should provide name as string" do
|
it "should provide name as string" do
|
|
@ -1,6 +1,4 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
|
||||||
|
|
||||||
class DummyProxyable < CouchRest::Model::Base
|
class DummyProxyable < CouchRest::Model::Base
|
||||||
proxy_database_method :db
|
proxy_database_method :db
|
||||||
|
@ -12,7 +10,7 @@ end
|
||||||
class ProxyKitten < CouchRest::Model::Base
|
class ProxyKitten < CouchRest::Model::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Proxyable" do
|
describe CouchRest::Model::Proxyable do
|
||||||
|
|
||||||
describe "#proxy_database" do
|
describe "#proxy_database" do
|
||||||
|
|
||||||
|
@ -87,7 +85,7 @@ describe "Proxyable" do
|
||||||
DummyProxyable.proxy_for(:cats)
|
DummyProxyable.proxy_for(:cats)
|
||||||
@obj = DummyProxyable.new
|
@obj = DummyProxyable.new
|
||||||
CouchRest::Model::Proxyable::ModelProxy.should_receive(:new).with(Cat, @obj, 'dummy_proxyable', 'db').and_return(true)
|
CouchRest::Model::Proxyable::ModelProxy.should_receive(:new).with(Cat, @obj, 'dummy_proxyable', 'db').and_return(true)
|
||||||
@obj.should_receive('proxy_database').and_return('db')
|
@obj.should_receive(:proxy_database).and_return('db')
|
||||||
@obj.cats
|
@obj.cats
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -165,15 +163,13 @@ describe "Proxyable" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should proxy new call" do
|
it "should proxy new call" do
|
||||||
Cat.should_receive(:new).and_return({})
|
@obj.should_receive(:proxy_block_update).with(:new, 'attrs', 'opts')
|
||||||
@obj.should_receive(:proxy_update).and_return(true)
|
@obj.new('attrs', 'opts')
|
||||||
@obj.new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should proxy build_from_database" do
|
it "should proxy build_from_database" do
|
||||||
Cat.should_receive(:build_from_database).and_return({})
|
@obj.should_receive(:proxy_block_update).with(:build_from_database, 'attrs', 'opts')
|
||||||
@obj.should_receive(:proxy_update).with({}).and_return(true)
|
@obj.build_from_database('attrs', 'opts')
|
||||||
@obj.build_from_database
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#method_missing" do
|
describe "#method_missing" do
|
||||||
|
@ -313,6 +309,15 @@ describe "Proxyable" do
|
||||||
@obj.send(:proxy_update_all, docs)
|
@obj.send(:proxy_update_all, docs)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#proxy_block_update" do
|
||||||
|
it "should proxy block updates" do
|
||||||
|
doc = { }
|
||||||
|
@obj.model.should_receive(:new).and_yield(doc)
|
||||||
|
@obj.should_receive(:proxy_update).with(doc)
|
||||||
|
@obj.send(:proxy_block_update, :new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
|
@ -1,8 +1,4 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
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')
|
|
||||||
|
|
||||||
# add a default value
|
# add a default value
|
||||||
Card.property :bg_color, :default => '#ccc'
|
Card.property :bg_color, :default => '#ccc'
|
|
@ -1,8 +1,5 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
require File.expand_path('../../spec_helper', __FILE__)
|
require 'spec_helper'
|
||||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
|
||||||
|
|
||||||
describe "Type Casting" do
|
describe "Type Casting" do
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
|
|
||||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
describe CouchRest::Model::Validations do
|
||||||
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')
|
|
||||||
|
|
||||||
# TODO Move validations from other specs to here
|
|
||||||
|
|
||||||
describe "Validations" do
|
|
||||||
|
|
||||||
describe "Uniqueness" do
|
describe "Uniqueness" do
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
require File.expand_path("../../spec_helper", __FILE__)
|
require "spec_helper"
|
||||||
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 "Model views" do
|
describe CouchRest::Model::Views do
|
||||||
|
|
||||||
class Unattached < CouchRest::Model::Base
|
class Unattached < CouchRest::Model::Base
|
||||||
property :title
|
property :title
|
||||||
|
@ -18,7 +14,6 @@ describe "Model views" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
describe "ClassMethods" do
|
describe "ClassMethods" do
|
||||||
# NOTE! Add more unit tests!
|
# NOTE! Add more unit tests!
|
||||||
|
|
Loading…
Reference in a new issue