ActiveRel

Makes Neo4j Relationships more or less act like ActiveRecord objects. See documentation at https://github.com/neo4jrb/neo4j/wiki/Neo4j%3A%3AActiveRel

Constants

  • WRAPPED_CLASSES
  • N1_N2_STRING
  • ACTIVEREL_NODE_MATCH_STRING
  • USES_CLASSNAME

Methods

#==

def ==(other)
  other.class == self.class && other.id == id
end
#[]

Returning nil when we get ActiveAttr::UnknownAttributeError from ActiveAttr

def read_attribute(name)
  super(name)
rescue ActiveAttr::UnknownAttributeError
  nil
end

#_active_record_destroyed_behavior?

def _active_record_destroyed_behavior?
  fail 'Remove this workaround in 6.0.0' if Neo4j::VERSION >= '6.0.0'

  !!Neo4j::Config[:_active_record_destroyed_behavior]
end
#_destroyed_double_check?

These two methods should be removed in 6.0.0

def _destroyed_double_check?
  if _active_record_destroyed_behavior?
    false
  else
    (!new_record? && !exist?)
  end
end
#_persisted_obj

Returns the value of attribute _persisted_obj

def _persisted_obj
  @_persisted_obj
end

#apply_default_values

def apply_default_values
  return if self.class.declared_property_defaults.empty?
  self.class.declared_property_defaults.each_pair do |key, value|
    self.send("#{key}=", value) if self.send(key).nil?
  end
end

#cache_key

def cache_key
  if self.new_record?
    "#{model_cache_key}/new"
  elsif self.respond_to?(:updated_at) && !self.updated_at.blank?
    "#{model_cache_key}/#{neo_id}-#{self.updated_at.utc.to_s(:number)}"
  else
    "#{model_cache_key}/#{neo_id}"
  end
end

#declared_property_manager

def declared_property_manager
  self.class.declared_property_manager
end
#destroy
nodoc:
def destroy #:nodoc:
  tx = Neo4j::Transaction.new
  run_callbacks(:destroy) { super }
rescue
  @_deleted = false
  @attributes = @attributes.dup
  tx.mark_failed
  raise
ensure
  tx.close if tx
end
#destroyed?

Returns +true+ if the object was destroyed.

def destroyed?
  @_deleted || _destroyed_double_check?
end

#end_node

alias_method :end_node,   :to_node

#eql?

def ==(other)
  other.class == self.class && other.id == id
end

#exist?

def exist?
  _persisted_obj && _persisted_obj.exist?
end

#freeze

def freeze
  @attributes.freeze
  self
end

#from_node_neo_id

alias_method :from_node_neo_id, :start_node_neo_id

#frozen?

def frozen?
  @attributes.frozen?
end

#hash

def hash
  id.hash
end

#id

def id
  id = neo_id
  id.is_a?(Integer) ? id : nil
end
#init_on_load

called when loading the rel from the database

def init_on_load(persisted_rel, from_node_id, to_node_id, type)
  @rel_type = type
  @_persisted_obj = persisted_rel
  changed_attributes && changed_attributes.clear
  @attributes = convert_and_assign_attributes(persisted_rel.props)
  load_nodes(from_node_id, to_node_id)
end

#initialize

def initialize(*args)
  load_nodes
  super
end

#inspect

def inspect
  attribute_pairs = attributes.sort.map { |key, value| "#{key}: #{value.inspect}" }
  attribute_descriptions = attribute_pairs.join(', ')
  separator = ' ' unless attribute_descriptions.empty?

  cypher_representation = "#{node_cypher_representation(from_node)}-[:#{type}]->#{node_cypher_representation(to_node)}"
  "#<#{self.class.name} #{cypher_representation}#{separator}#{attribute_descriptions}>"
end

#neo4j_obj

def neo4j_obj
  _persisted_obj || fail('Tried to access native neo4j object on a non persisted object')
end

#neo_id

def neo_id
  _persisted_obj ? _persisted_obj.neo_id : nil
end
#new?

Returns +true+ if the record hasn’t been saved to Neo4j yet.

def new_record?
  !_persisted_obj
end
#new_record?

Returns +true+ if the record hasn’t been saved to Neo4j yet.

def new_record?
  !_persisted_obj
end

#node_cypher_representation

def node_cypher_representation(node)
  node_class = node.class
  id_name = node_class.id_property_name
  labels = ':' + node_class.mapped_label_names.join(':')

  "(#{labels} {#{id_name}: #{node.id.inspect}})"
end
#persisted?

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

#props

def props
  attributes.reject { |_, v| v.nil? }.symbolize_keys
end
#props_for_create

Returns a hash containing: * All properties and values for insertion in the database * A uuid (or equivalent) key and value * A _classname property, if one is to be set * Timestamps, if the class is set to include them. Note that the UUID is added to the hash but is not set on the node. The timestamps, by comparison, are set on the node prior to addition in this hash.

def props_for_create
  inject_timestamps!
  converted_props = props_for_db(props)
  inject_classname!(converted_props)
  inject_defaults!(converted_props)
  return converted_props unless self.class.respond_to?(:default_property_values)
  inject_primary_key!(converted_props)
end

#props_for_persistence

def props_for_persistence
  _persisted_obj ? props_for_update : props_for_create
end

#props_for_update

def props_for_update
  update_magic_properties
  changed_props = attributes.select { |k, _| changed_attributes.include?(k) }
  changed_props.symbolize_keys!
  props_for_db(changed_props)
  inject_defaults!(changed_props)
end
#read_attribute

Returning nil when we get ActiveAttr::UnknownAttributeError from ActiveAttr

def read_attribute(name)
  super(name)
rescue ActiveAttr::UnknownAttributeError
  nil
end
#read_attribute_for_validation

Implements the ActiveModel::Validation hook method.

def read_attribute_for_validation(key)
  respond_to?(key) ? send(key) : self[key]
end

#rel_type

def type
  self.class.type
end

#reload

def reload
  return self if new_record?
  association_proxy_cache.clear if respond_to?(:association_proxy_cache)
  changed_attributes && changed_attributes.clear
  unless reload_from_database
    @_deleted = true
    freeze
  end
  self
end

#reload_from_database

def reload_from_database
  # TODO: - Neo4j::IdentityMap.remove_node_by_id(neo_id)
  if reloaded = self.class.load_entity(neo_id)
    send(:attributes=, reloaded.attributes)
  end
  reloaded
end

#save

def save(*args)
  unless _persisted_obj || (from_node.respond_to?(:neo_id) && to_node.respond_to?(:neo_id))
    fail Neo4j::ActiveRel::Persistence::RelInvalidError, 'from_node and to_node must be node objects'
  end
  super(*args)
end

#save!

def save!(*args)
  fail RelInvalidError, self unless save(*args)
end

#send_props

def send_props(hash)
  return hash if hash.blank?
  hash.each { |key, value| self.send("#{key}=", value) }
end

#serializable_hash

def serializable_hash(*args)
  super.merge(id: id)
end

#serialized_properties

def serialized_properties
  self.class.serialized_properties
end

#start_node

alias_method :start_node, :from_node
#to_key

Returns an Enumerable of all (primary) key attributes or nil if model.persisted? is false

def to_key
  _persisted_obj ? [id] : nil
end

#to_node_neo_id

alias_method :to_node_neo_id,   :end_node_neo_id
#touch
nodoc:
def touch #:nodoc:
  run_callbacks(:touch) { super }
end

#type

def type
  self.class.type
end
#update

Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved. If saving fails because the resource is invalid then false will be returned.

def update(attributes)
  self.attributes = process_attributes(attributes)
  save
end
#update!

Same as {#update_attributes}, but raises an exception if saving fails.

def update!(attributes)
  self.attributes = process_attributes(attributes)
  save!
end
#update_attribute

Convenience method to set attribute and #save at the same time

def update_attribute(attribute, value)
  send("#{attribute}=", value)
  self.save
end
#update_attribute!

Convenience method to set attribute and #save! at the same time

def update_attribute!(attribute, value)
  send("#{attribute}=", value)
  self.save!
end
#update_attributes

Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved. If saving fails because the resource is invalid then false will be returned.

def update(attributes)
  self.attributes = process_attributes(attributes)
  save
end
#update_attributes!

Same as {#update_attributes}, but raises an exception if saving fails.

def update!(attributes)
  self.attributes = process_attributes(attributes)
  save!
end

#valid?

def valid?(context = nil)
  context ||= (new_record? ? :create : :update)
  super(context)
  errors.empty?
end
#wrapper

Implements the Neo4j::Node#wrapper and Neo4j::Relationship#wrapper method so that we don’t have to care if the node is wrapped or not.

def wrapper
  self
end