ruprict/oriented

View on GitHub
lib/oriented/persistence.rb

Summary

Maintainability
A
35 mins
Test Coverage
require 'active_support/concern'

module Oriented
    module Persistence
      
      extend ActiveSupport::Concern
      extend Oriented::Core::TransactionWrapper


      # Persist the object to the database.  Validations and Callbacks are included
      # by default but validation can be disabled by passing <tt>:validate => false</tt>
      # to <tt>save</tt>. Creates a new transaction.
      # @param (see Neo4j::Rails::Validations#save)
      # @return [Boolean] true if it was persisted
      # @see Neo4j::Rails::Validations Neo4j::Rails::Validations - for the :validate parameter
      # @see Neo4j::Rails::Callbacks Neo4j::Rails::Callbacks - for callbacks
      def save(*)
        create_or_update
        # __java_obj.save
      end
      wrap_in_transaction :save


      # Removes the node from Neo4j and freezes the object.
      def destroy
        delete
        # freeze
      end

      # Same as #destroy but doesn't run destroy callbacks and doesn't freeze
      # the object. Creates a new transaction
      def delete
        __java_obj.remove unless new_record? || destroyed?
        set_deleted_properties
        # __java_obj.record.reload if __java_obj
      end
      wrap_in_transaction :delete

      # Returns +true+ if the object was destroyed.
      def destroyed?
        @_deleted # || (!new_record? && !self.class.load_entity(_orient_id))
      end

      # Returns +true+ if the record is persisted, i.e. it’s not a new record and it was not destroyed
      def persisted?
        !new_record? && !destroyed?
      end

      # Returns +true+ if the record hasn't been saved to Neo4j yet.
      def new_record?
        __java_obj.nil?
      end

      alias :new? :new_record?

      # Freeze the properties hash.
      def freeze
        @_properties.freeze
        self
      end

      # Returns +true+ if the properties hash has been frozen.
      def frozen?
        freeze_if_deleted
        @_properties.frozen?
      end

      module ClassMethods
        class << self
          include Oriented::Core::TransactionWrapper
        end

        def transaction(&block)
          # Neo4j::Rails::Transaction.run do |tx|
          #   block.call(tx)
          # end
        end

        def new(*args, &block)
          instance = orig_new(*args, &block)
          # instance = super(*args, &block)          
          instance.instance_eval(&block) if block
          instance
        end

        def get(rid)
          get!(rid)
        end
        
        
        # Initialize a model and set a bunch of attributes at the same time.  Returns
        # the object whether saved successfully or not.
        def create(*args)
          new(*args).tap do |o|
            yield o if block_given?
            o.save
          end
        end

        # Get the indexed entity, creating it (exactly once) if no indexed entity exist.
        #
        # @example Creating a Unique node
        #
        #   class MyNode < Neo4j::Rails::Model
        #     property :email, :index => :exact, :unique => true
        #   end
        #
        #   node = MyNode.get_or_create(:email =>'jimmy@gmail.com', :name => 'jimmy')
        #
        # @see #put_if_absent
        def get_or_create(*args)
          props = args.first

          props.keys.each do |key|
            props[key.to_s] = props.delete(key)
          end

          idx = self.oclass.indexes.first
          
          vtx = Oriented.connection.graph.get_vertices(idx.name, props[idx.definition.fields[0]]).to_a if idx && props[idx.definition.fields[0]]
          if vtx && vtx.first
            return vtx.first.wrapper
          else
            obj = self.new(props).wrapper
            obj.save
            return obj
          end
          # raise "Can't get or create entity since #{props.inspect} does not included unique key #{props[unique_factory_key]}'" unless props[unique_factory_key]
          # index = index_for_type(_decl_props[unique_factory_key][:index])
          # Neo4j::Core::Index::UniqueFactory.new(unique_factory_key, index) { |*| create!(*args) }.get_or_create(unique_factory_key, props[unique_factory_key]).wrapper
        end
        wrap_in_transaction :get_or_create

        # Same as #create, but raises an error if there is a problem during save.
        # @return [Neo4j::Rails::Model, Neo4j::Rails::Relationship]
        def create!(*args)
          new(*args).tap do |o|
            yield o if block_given?
            o.save!
          end
        end

        # Destroy each node in turn.  Runs the destroy callbacks for each node.
        def destroy_all
          all.each do |n|
            n.destroy
          end
        end
        
        def destroy(obj)
          obj.destroy
        end
        
      end

      # Returns if the entity is currently being updated or created
      def create_or_updating?
        !!@_create_or_updating
      end


      def update_attributes(attrs)
        attrs.each_pair do |k,v|
          self.public_send("#{k}=", v)
        end
      end

      protected

      def update
        write_changed_attributes
        true
      end

      def create_or_update
        # since the same model can be created or updated twice from a relationship we have to have this guard
        @_create_or_updating = true
              result = persisted? ? update : create
              unless result != false
                false
              else
                true
              end
            rescue => e
              raise e
            ensure
              @_create_or_updating = nil
      end

      def set_deleted_properties
        @_deleted = true
      end

      public
      class RecordInvalidError < RuntimeError
        attr_reader :record

        def initialize(record)
          @record = record
          super
          # super(@record.errors.full_messages.join(", "))
        end
      end
    end
end