ActiveRel

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

Constants

  • MARSHAL_INSTANCE_VARIABLES
  • WRAPPED_CLASSES
  • DATE_KEY_REGEX

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
#_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
#concurrent_increment!

Increments concurrently a numeric attribute by a centain amount

def concurrent_increment!(attribute, by = 1)
  query_rel = Neo4j::Session.query.match('()-[n]-()').where(n: {neo_id: neo_id})
  increment_by_query! query_rel, attribute, by
end
#conditional_callback

Allows you to perform a callback if a condition is not satisfied.

def conditional_callback(kind, guard)
  return yield if guard
  run_callbacks(kind) { yield }
end

#create_method

def create_method
  self.class.create_method
end

#creates_unique_option

def creates_unique_option
  self.class.creates_unique_option
end

#cypher_identifier

def cypher_identifier
  @cypher_identifier || :rel
end

#declared_properties

def declared_properties
  self.class.declared_properties
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
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_identifier

def from_node_identifier
  @from_node_identifier || :from_node
end

#from_node_identifier=

def from_node_identifier=(id)
  @from_node_identifier = id.to_sym
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
#increment

Increments a numeric attribute by a centain amount

def increment(attribute, by = 1)
  self[attribute] ||= 0
  self[attribute] += by
  self
end
#increment!

Convenience method to increment numeric attribute and #save at the same time

def increment!(attribute, by = 1)
  increment(attribute, by).update_attribute(attribute, self[attribute])
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

#init_on_reload

def init_on_reload(unwrapped_reloaded)
  @attributes = nil
  init_on_load(unwrapped_reloaded,
               unwrapped_reloaded._start_node_id,
               unwrapped_reloaded._end_node_id,
               unwrapped_reloaded.rel_type)
  self
end

#initialize

def initialize(from_node = nil, to_node = nil, args = nil)
  load_nodes(node_or_nil(from_node), node_or_nil(to_node))
  resolved_args = hash_or_nil(from_node, args)
  symbol_args = resolved_args.is_a?(Hash) ? resolved_args.symbolize_keys : resolved_args
  super(symbol_args)
end

#inject_defaults!

def inject_defaults!(starting_props)
  return starting_props if self.class.declared_properties.declared_property_defaults.empty?
  self.class.declared_properties.inject_defaults!(self, starting_props || {})
end

#inspect

def inspect
  attribute_descriptions = inspect_attributes.map do |key, value|
    "#{Neo4j::ANSI::CYAN}#{key}: #{Neo4j::ANSI::CLEAR}#{value.inspect}"
  end.join(', ')

  separator = ' ' unless attribute_descriptions.empty?
  "#<#{Neo4j::ANSI::YELLOW}#{self.class.name}#{Neo4j::ANSI::CLEAR}#{separator}#{attribute_descriptions}>"
end

#marshal_dump

def marshal_dump
  marshal_instance_variables.map(&method(:instance_variable_get))
end

#marshal_load

def marshal_load(array)
  marshal_instance_variables.zip(array).each do |var, value|
    instance_variable_set(var, value)
  end
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 * 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!
  props_with_defaults = inject_defaults!(props)
  converted_props = props_for_db(props_with_defaults)
  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!
  inject_defaults!(changed_props)
  props_for_db(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
  reloaded = self.class.load_entity(neo_id)
  reloaded ? init_on_reload(reloaded._persisted_obj) : nil
end

#reload_properties!

def reload_properties!(properties)
  @attributes = nil
  convert_and_assign_attributes(properties)
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)
  save(*args) or fail(RelInvalidError, inspect) # rubocop:disable Style/AndOr
end

#send_props

def send_props(hash)
  return hash if hash.blank?
  hash.each { |key, value| 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_identifier

def to_node_identifier
  @to_node_identifier || :to_node
end

#to_node_identifier=

def to_node_identifier=(id)
  @to_node_identifier = id.to_sym
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