diff --git a/history.md b/history.md index 695379a..0841c44 100644 --- a/history.md +++ b/history.md @@ -2,9 +2,13 @@ ## 1.1.0 - 2011-05-XX +* New Features + * Properties with a nil value are now no longer sent to the database. + * Now possible to build new objects via CastedArray#build + * Implement #get! and #find! class methods + * Minor fixes * #as_json now correctly uses ActiveSupports methods. - * nil properties are now no longer sent in the document body. * Rails 3.1 support (Peter Williams) * Initialization blocks when creating new models (Peter Williams) * Removed railties dependency (DAddYE) diff --git a/lib/couchrest/model/casted_array.rb b/lib/couchrest/model/casted_array.rb index 6737b46..8e4ff66 100644 --- a/lib/couchrest/model/casted_array.rb +++ b/lib/couchrest/model/casted_array.rb @@ -50,6 +50,12 @@ module CouchRest::Model super end + def build(*args) + obj = casted_by_property.build(*args) + self.push(obj) + obj + end + protected def instantiate_and_cast(obj, change = true) diff --git a/lib/couchrest/model/class_proxy.rb b/lib/couchrest/model/class_proxy.rb index 3f988b1..16887a3 100644 --- a/lib/couchrest/model/class_proxy.rb +++ b/lib/couchrest/model/class_proxy.rb @@ -87,7 +87,14 @@ module CouchRest doc end 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 def has_view?(view) diff --git a/lib/couchrest/model/document_queries.rb b/lib/couchrest/model/document_queries.rb index af1083d..839674b 100644 --- a/lib/couchrest/model/document_queries.rb +++ b/lib/couchrest/model/document_queries.rb @@ -86,9 +86,12 @@ module CouchRest # id:: Document ID # db:: optional option to pass a custom database to use 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 build_from_database(doc) + rescue RestClient::ResourceNotFound + raise CouchRest::Model::DocumentNotFound end alias :find! :get! diff --git a/lib/couchrest/model/errors.rb b/lib/couchrest/model/errors.rb index 7f14fca..45d8b2f 100644 --- a/lib/couchrest/model/errors.rb +++ b/lib/couchrest/model/errors.rb @@ -19,5 +19,7 @@ module CouchRest end end end + + class DocumentNotFound < Errors::CouchRestModelError; end end end diff --git a/lib/couchrest/model/persistence.rb b/lib/couchrest/model/persistence.rb index 977bbe2..885f726 100644 --- a/lib/couchrest/model/persistence.rb +++ b/lib/couchrest/model/persistence.rb @@ -21,8 +21,8 @@ module CouchRest # Creates the document in the db. Raises an exception # if the document is not created properly. - def create! - self.class.fail_validate!(self) unless self.create + def create!(options = {}) + self.class.fail_validate!(self) unless self.create(options) end # Trigger the callbacks (before, after, around) @@ -120,8 +120,8 @@ module CouchRest # # ==== Returns # returns the reloaded document - def create(attributes = {}) - instance = new(attributes) + def create(attributes = {}, &block) + instance = new(attributes, &block) instance.create instance end @@ -130,8 +130,8 @@ module CouchRest # # ==== Returns # returns the reloaded document or raises an exception - def create!(attributes = {}) - instance = new(attributes) + def create!(attributes = {}, &block) + instance = new(attributes, &block) instance.create! instance end diff --git a/lib/couchrest/model/property.rb b/lib/couchrest/model/property.rb index baa71ce..7661858 100644 --- a/lib/couchrest/model/property.rb +++ b/lib/couchrest/model/property.rb @@ -64,6 +64,18 @@ module CouchRest::Model end end + # Initialize a new instance of a property's type ready to be + # used. If a proc is defined for the init method, it will be used instead of + # a normal call to the class. + def build(*args) + raise StandardError, "Cannot build property without a class" if @type_class.nil? + if @init_method.is_a?(Proc) + @init_method.call(*args) + else + @type_class.send(@init_method, *args) + end + end + private def associate_casted_value_to_parent(parent, value) diff --git a/lib/couchrest/model/typecast.rb b/lib/couchrest/model/typecast.rb index 6e1113d..6858335 100644 --- a/lib/couchrest/model/typecast.rb +++ b/lib/couchrest/model/typecast.rb @@ -14,8 +14,7 @@ module CouchRest elsif [String, TrueClass, Integer, Float, BigDecimal, DateTime, Time, Date, Class].include?(klass) send('typecast_to_'+klass.to_s.downcase, value) else - # Allow the init_method to be defined as a Proc for advanced conversion - property.init_method.is_a?(Proc) ? property.init_method.call(value) : klass.send(property.init_method, value) + property.build(value) end end diff --git a/spec/couchrest/class_proxy_spec.rb b/spec/couchrest/class_proxy_spec.rb index f274ca9..1572d8d 100644 --- a/spec/couchrest/class_proxy_spec.rb +++ b/spec/couchrest/class_proxy_spec.rb @@ -123,6 +123,35 @@ describe "Proxy Class" do u.respond_to?(:database).should be_false 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 # Removed as unclear why this should happen as before my changes # this happend by accident, not explicitly. diff --git a/spec/couchrest/persistence_spec.rb b/spec/couchrest/persistence_spec.rb index 4c0014c..cd2ebed 100644 --- a/spec/couchrest/persistence_spec.rb +++ b/spec/couchrest/persistence_spec.rb @@ -82,6 +82,18 @@ describe "Model Persistence" do article.should_not be_new 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 doc = WithCallBacks.create(:name => 'my other test') doc.run_before_create.should be_true diff --git a/spec/couchrest/property_spec.rb b/spec/couchrest/property_spec.rb index 08ea325..bb55bfc 100644 --- a/spec/couchrest/property_spec.rb +++ b/spec/couchrest/property_spec.rb @@ -358,6 +358,28 @@ describe "Property Class" do property.init_method.should eql('parse') end + describe "#build" do + it "should allow instantiation of new object" do + property = CouchRest::Model::Property.new(:test, Date) + obj = property.build(2011, 05, 21) + obj.should eql(Date.new(2011, 05, 21)) + end + it "should use init_method if provided" do + property = CouchRest::Model::Property.new(:test, Date, :init_method => 'parse') + obj = property.build("2011-05-21") + obj.should eql(Date.new(2011, 05, 21)) + end + it "should use init_method Proc if provided" do + property = CouchRest::Model::Property.new(:test, Date, :init_method => Proc.new{|v| Date.parse(v)}) + obj = property.build("2011-05-21") + obj.should eql(Date.new(2011, 05, 21)) + end + it "should raise error if no class" do + property = CouchRest::Model::Property.new(:test) + lambda { property.build }.should raise_error(StandardError, /Cannot build/) + end + end + ## Property Casting method. More thoroughly tested in typecast_spec. describe "casting" do @@ -386,6 +408,18 @@ describe "Property Class" do property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should eql(CouchRest::Model::CastedArray) end + it "should allow instantion of model via CastedArray#build" do + property = CouchRest::Model::Property.new(:dates, [Date]) + parent = Article.new + ary = property.cast(parent, []) + obj = ary.build(2011, 05, 21) + ary.length.should eql(1) + ary.first.should eql(Date.new(2011, 05, 21)) + obj = ary.build(2011, 05, 22) + ary.length.should eql(2) + ary.last.should eql(Date.new(2011, 05, 22)) + end + it "should raise and error if value is array when type is not" do property = CouchRest::Model::Property.new(:test, Date) parent = mock("FooClass")