Commits

Sean Cribbs committed 2662df5

Initial implementation of linked associations.

  • Participants
  • Parent commits 7919e4a

Comments (0)

Files changed (8)

ripple/lib/ripple/associations.rb

     autoload :One
     autoload :Many
     autoload :Embedded
+    autoload :Linked
     autoload :Instantiators
     autoload :OneEmbeddedProxy
     autoload :ManyEmbeddedProxy
+    autoload :OneLinkedProxy
+    autoload :ManyLinkedProxy
 
     module ClassMethods
       # @private
     end
 
     def proxy_class_name
-      @using   ||= options[:using] || (embeddable? ? :embedded : :link)
+      @using   ||= options[:using] || (embeddable? ? :embedded : :linked)
       klass_name = (many? ? 'Many' : 'One') + @using.to_s.camelize + ('Polymorphic' if polymorphic?).to_s + 'Proxy'
       "Ripple::Associations::#{klass_name}"
     end

ripple/lib/ripple/associations/linked.rb

 module Ripple
   module Associations
     module Linked
-
-      def create(attrs={})
-        instantiate_target(:create, attrs)
+      # TODO: decide whether to save owner automatically
+      def replace(value)
+        @owner.robject.links -= links
+        Array(value).compact.each do |doc|
+          @owner.robject.links << doc.robject.to_link(@reflection.name)
+        end
+        loaded
+        @target = value
       end
 
-      def create!(attrs={})
-        instantiate_target(:create!, attrs)
+      protected
+      def links
+        @owner.robject.links.select {|l| l.tag == @reflection.name.to_s }
       end
 
+      def robjects
+        @owner.robject.walk(:tag => @reflection.name).first
+      rescue
+        []
+      end
     end
   end
 end

ripple/lib/ripple/associations/many.rb

         @target = []
       end
 
-      def <<
-          raise NotImplementedError
+      def <<(value)
+        raise NotImplementedError
       end
+
       alias_method :push, :<<
-        alias_method :concat, :<<
+      alias_method :concat, :<<
 
-        protected
+      protected
       def instantiate_target(instantiator, attrs={})
         doc = klass.send(instantiator, attrs)
         self << doc

ripple/lib/ripple/associations/many_linked_proxy.rb

+# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+require 'ripple'
+
+module Ripple
+  module Associations
+    class ManyLinkedProxy < Proxy
+      include Many
+      include Linked
+
+      def <<(value)
+        # TODO: verify inputs!
+        load_target
+        new_target = @target.concat(Array(value))
+        replace new_target
+        self
+      end
+
+      protected
+      def find_target
+        robjects.map {|robj| klass.send(:instantiate, robj) }
+      end
+    end
+  end
+end

ripple/lib/ripple/associations/one_embedded_proxy.rb

           assign_references(doc)
         end
       end
-
     end
   end
 end

ripple/lib/ripple/associations/one_linked_proxy.rb

+# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+require 'ripple'
+
+module Ripple
+  module Associations
+    class OneLinkedProxy < Proxy
+      include One
+      include Linked
+
+      protected
+      def find_target
+        return nil if links.blank?
+        klass.send(:instantiate,robjects.first)
+      end
+    end
+  end
+end

ripple/lib/ripple/document/persistence.rb

           @attributes.freeze; super
         end
 
-        protected
         attr_writer :robject
 
         def robject

ripple/spec/integration/ripple/associations_spec.rb

         one  :profile
         many :addresses
         property :email, String, :presence => true
+        many :friends, :class_name => "User"
+        one :emergency_contact, :class_name => "User"
       end
       class Profile
         include Ripple::EmbeddedDocument
     @profile  = Profile.new(:name => 'Ripple')
     @billing  = Address.new(:street => '123 Somewhere Dr', :kind => 'billing')
     @shipping = Address.new(:street => '321 Anywhere Pl', :kind => 'shipping')
+    @friend1 = User.create(:email => "friend@ripple.com")
+    @friend2 = User.create(:email => "friend2@ripple.com")
   end
   
   it "should save one embedded associations" do
     @bill.should be_a(Address)
     @ship.should be_a(Address)
   end
+
+  it "should save a many linked association" do    
+    @user.friends << @friend1 << @friend2
+    @user.save
+    @user.should_not be_new_record
+    @found = User.find(@user.key)
+    @found.friends.map(&:key).should include(@friend1.key)
+    @found.friends.map(&:key).should include(@friend2.key)
+  end
+
+  it "should save a one linked association" do
+    @user.emergency_contact = @friend1
+    @user.save
+    @user.should_not be_new_record
+    @found = User.find(@user.key)
+    @found.emergency_contact.key.should == @friend1.key
+  end
   
   after :each do
     User.destroy_all