<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -12,3 +12,18 @@ IRB.conf[:SAVE_HISTORY] = 100
 IRB.conf[:HISTORY_FILE] = &quot;.irb_history&quot;
 
 IRB.conf[:PROMPT_MODE] = :SIMPLE
+
+def use_spec_db
+  RelaxDB.configure :host =&gt; &quot;localhost&quot;, :port =&gt; 5984, :design_doc =&gt; &quot;spec_doc&quot;, :logger =&gt; Logger.new(STDOUT)
+  RelaxDB.use_db &quot;relaxdb_spec&quot; 
+  RelaxDB.enable_view_creation
+end
+
+def new_spec_db
+  RelaxDB.configure :host =&gt; &quot;localhost&quot;, :port =&gt; 5984, :design_doc =&gt; &quot;spec_doc&quot;, :logger =&gt; Logger.new(STDOUT)
+  RelaxDB.delete_db &quot;relaxdb_spec&quot; rescue &quot;ok&quot;
+  RelaxDB.use_db &quot;relaxdb_spec&quot; 
+  RelaxDB.replicate_db &quot;relaxdb_spec_base&quot;, &quot;relaxdb_spec&quot;
+  RelaxDB.enable_view_creation
+end
+</diff>
      <filename>.irbrc</filename>
    </modified>
    <modified>
      <diff>@@ -61,6 +61,7 @@ module RelaxDB
   
     property :_id 
     property :_rev        
+    property :_conflicts        
     
     def self.create_validator(att, v)
       method_name = &quot;validate_#{att}&quot;
@@ -198,17 +199,25 @@ module RelaxDB
         resp = RelaxDB.db.put(_id, to_json)
         self._rev = JSON.parse(resp.body)[&quot;rev&quot;]
       rescue HTTP_409
-        on_update_conflict
-        @update_conflict = true
+        conflicted
         return false
       end      
     end
     
+    def conflicted
+      @update_conflict = true
+      on_update_conflict
+    end    
+    
     def on_update_conflict
       # override with any behaviour you want to happen when
       # CouchDB returns DocumentConflict on an attempt to save
     end
     
+    def update_conflict?
+      @update_conflict
+    end    
+    
     def pre_save
       set_timestamps
       return false unless validates?
@@ -238,11 +247,7 @@ module RelaxDB
         raise ValidationFailure, self.errors.to_json
       end
     end
-        
-    def update_conflict?
-      @update_conflict
-    end
-    
+            
     def validates?
       props = properties - validation_skip_list
       prop_vals = props.map { |prop| instance_variable_get(&quot;@#{prop}&quot;) }</diff>
      <filename>lib/relaxdb/document.rb</filename>
    </modified>
    <modified>
      <diff>@@ -67,25 +67,35 @@ module RelaxDB
     end
     
     def bulk_save!(*objs)
+      if objs[0].equal? :all_or_nothing
+        objs.shift
+        all_or_nothing = true
+      end
+      
       pre_save_success = objs.inject(true) { |s, o| s &amp;= o.pre_save }
       raise ValidationFailure, objs unless pre_save_success
       
       docs = {}
       objs.each { |o| docs[o._id] = o }
       
-      begin
-        resp = db.post(&quot;_bulk_docs&quot;, { &quot;docs&quot; =&gt; objs }.to_json )
-        data = JSON.parse(resp.body)
-    
-        data.each do |new_rev|
-          obj = docs[ new_rev[&quot;id&quot;] ]
+      data = { &quot;docs&quot; =&gt; objs }
+      data[:all_or_nothing] = true if all_or_nothing
+      resp = db.post(&quot;_bulk_docs&quot;, data.to_json )
+      data = JSON.parse(resp.body)
+  
+      conflicted = false
+      data.each do |new_rev|
+        obj = docs[ new_rev[&quot;id&quot;] ]
+        if new_rev[&quot;rev&quot;]
           obj._rev = new_rev[&quot;rev&quot;]
           obj.post_save
+        else
+          conflicted = true
+          obj.conflicted
         end
-      rescue HTTP_409
-        raise UpdateConflict, objs
       end
-    
+  
+      raise UpdateConflict if conflicted    
       objs
     end
     
@@ -101,7 +111,12 @@ module RelaxDB
       load(obj._id)
     end
   
-    def load(ids)
+    #
+    # Examples:
+    #   RelaxDB.load &quot;foo&quot;, :conflicts =&gt; true
+    #   RelaxDB.load [&quot;foo&quot;, &quot;bar&quot;]
+    #
+    def load(ids, atts={})
       # RelaxDB.logger.debug(caller.inject(&quot;#{db.name}/#{ids}\n&quot;) { |a, i| a += &quot;#{i}\n&quot; })
       
       if ids.is_a? Array
@@ -110,9 +125,11 @@ module RelaxDB
         data[&quot;rows&quot;].map { |row| row[&quot;doc&quot;] ? create_object(row[&quot;doc&quot;]) : nil }
       else
         begin
-          resp = db.get(ids)
-          data = JSON.parse(resp.body)
-          create_object(data)
+          qs = atts.map{ |k, v| &quot;#{k}=#{v}&quot; }.join(&quot;&amp;&quot;)
+          qs = atts.empty? ? ids : &quot;#{ids}?#{qs}&quot;
+          resp = db.get qs
+          data = JSON.parse resp.body
+          create_object data
         rescue HTTP_404
           nil
         end</diff>
      <filename>lib/relaxdb/relaxdb.rb</filename>
    </modified>
    <modified>
      <diff>@@ -15,7 +15,7 @@ module RelaxDB
     def initialize(config)
       @get_count, @post_count, @put_count = 0, 0, 0
       @server = RelaxDB::Server.new(config[:host], config[:port])
-      @logger = config[:logger] ? config[:logger] : Logger.new(Tempfile.new('couchdb.log'))
+      @logger = config[:logger] ? config[:logger] : Logger.new(Tempfile.new('relaxdb.log'))
     end
     
     def use_db(name)</diff>
      <filename>lib/relaxdb/server.rb</filename>
    </modified>
    <modified>
      <diff>@@ -73,7 +73,7 @@ describe &quot;Inheritance&quot; do
   describe &quot;derived properties&quot; do
     
     it &quot;should be stored&quot; do
-      u = User.new(:name =&gt; &quot;u&quot;).save!
+      u = User.new(:_id =&gt; &quot;foo&quot;, :name =&gt; &quot;u&quot;).save!
       s = SubDescendant.new(:user =&gt; u).save!
       r = RichDescendant.new(:user =&gt; u, :ukulele =&gt; u).save!
       </diff>
      <filename>spec/doc_inheritable_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -70,6 +70,45 @@ describe RelaxDB do
       RelaxDB.bulk_save(x).first.foo.should == :bar
     end
     
+    it &quot;should save non conflicting docs and mark conflicting docs&quot; do
+      p1, p2 = Atom.new.save!, Atom.new.save!
+      p1.dup.save!
+      RelaxDB.bulk_save p1, p2
+      p1._rev.should =~ /1-/
+      p1.should be_update_conflict
+      p2._rev.should =~ /2-/
+    end
+    
+    # The spec is as much a verification of my understanding of
+    # bulk_save semantics as it is a test of RelaxDB
+    describe &quot;all-or-nothing&quot; do
+      it &quot;should save non conflicting and conflicting docs&quot; do
+        p1, p2 = Primitives.new(:num =&gt; 1).save!, Primitives.new(:num =&gt; 2).save!
+        p1d = p1.dup
+        p1d.num = 11
+        p1d.save!
+        p1.num = 6
+        RelaxDB.bulk_save :all_or_nothing, p1, p2
+        p1._rev.should =~ /2-/
+        p2._rev.should =~ /2-/
+        
+        p1 = RelaxDB.load p1._id, :conflicts =&gt; true
+        p1.num.should == 11
+        p1 = RelaxDB.load p1._id, :rev =&gt; p1._conflicts[0]
+        p1.num.should == 6
+      end
+      
+      it &quot;non-deterministic winner&quot; do
+        p = Primitives.new(:num =&gt; 1).save!
+        pd = p.dup
+        p.num = 2
+        p.save!
+        pd.num = 3
+        RelaxDB.bulk_save :all_or_nothing, pd
+        RelaxDB.reload(p).num.should == 2
+      end
+    end
+        
   end
   
   describe &quot;.bulk_save!&quot; do
@@ -81,9 +120,11 @@ describe RelaxDB do
       lambda { RelaxDB.bulk_save!(c.new) }.should raise_error(RelaxDB::ValidationFailure)
     end
     
-    it &quot;will not raise an exception if a document update conflict occurs on save&quot; do
-      Atom.new(:_id =&gt; &quot;a1&quot;).save!
-      RelaxDB.bulk_save! Atom.new(:_id =&gt; &quot;a1&quot;)
+    it &quot;should raise an exception on document conflict after all docs have been processed&quot; do
+      p1, p2 = Atom.new.save!, Atom.new.save!
+      p1.dup.save!
+      lambda { RelaxDB.bulk_save!(p1, p2) }.should raise_error(RelaxDB::UpdateConflict)
+      p2._rev.should =~ /2-/
     end
     
   end</diff>
      <filename>spec/relaxdb_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -180,7 +180,7 @@ class RichDescendant &lt; Descendant
   
   references :ukulele
   property :ukulele_name,
-    :derived =&gt; [:ukulele, lambda { |p, o| o.user.name } ]
+    :derived =&gt; [:ukulele, lambda { |p, o| o.ukulele.name } ]
 end
 
 module Inh</diff>
      <filename>spec/spec_models.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>f45f7ca012501f2ecab1dc5715afedc0c9e873b6</id>
    </parent>
  </parents>
  <author>
    <name>Paul Carey</name>
    <email>paul.p.carey@gmail.com</email>
  </author>
  <url>http://github.com/paulcarey/relaxdb/commit/665d4e932cc991e21a778a4f051ddeb0b8b617ba</url>
  <id>665d4e932cc991e21a778a4f051ddeb0b8b617ba</id>
  <committed-date>2009-05-22T05:05:40-07:00</committed-date>
  <authored-date>2009-05-22T05:05:40-07:00</authored-date>
  <message>Added support for all_or_nothing bulk_docs save.</message>
  <tree>b6234b33890af175615b27f22df4c79f1ec384d3</tree>
  <committer>
    <name>Paul Carey</name>
    <email>paul.p.carey@gmail.com</email>
  </committer>
</commit>
