module Neo4j::ActiveNode::HasN::ClassMethods

Public Instance Methods

association?(name) click to toggle source

rubocop:enable Style/PredicateName

    # File lib/neo4j/active_node/has_n.rb
228 def association?(name)
229   !!associations[name.to_sym]
230 end
associations() click to toggle source
    # File lib/neo4j/active_node/has_n.rb
232 def associations
233   @associations ||= {}
234 end
associations_keys() click to toggle source
    # File lib/neo4j/active_node/has_n.rb
236 def associations_keys
237   @associations_keys ||= associations.keys
238 end
has_association?(name) click to toggle source

:nocov:

    # File lib/neo4j/active_node/has_n.rb
219 def has_association?(name)
220   ActiveSupport::Deprecation.warn 'has_association? is deprecated and may be removed from future releases, use association? instead.', caller
221 
222   association?(name)
223 end
has_many(direction, name, options = {}) click to toggle source

For defining an “has many” association on a model. This defines a set of methods on your model instances. For instance, if you define the association on a Person model:

.. code-block

ruby

has_many :out, :vehicles, type: :has_vehicle

This would define the following methods:

#vehicles

Returns a QueryProxy object.  This is an Enumerable object and thus can be iterated
over.  It also has the ability to accept class-level methods from the Vehicle model
(including calls to association methods)

**#vehicles=**

Takes an array of Vehicle objects and replaces all current ``:HAS_VEHICLE`` relationships
with new relationships refering to the specified objects

.vehicles

Returns a QueryProxy object.  This would represent all ``Vehicle`` objects associated with
either all ``Person`` nodes (if ``Person.vehicles`` is called), or all ``Vehicle`` objects
associated with the ``Person`` nodes thus far represented in the QueryProxy chain.
For example:

.. code-block:: ruby

  company.people.where(age: 40).vehicles

Arguments:

**direction:**
  **Available values:** ``:in``, ``:out``, or ``:both``.

  Refers to the relative to the model on which the association is being defined.

  Example:

  .. code-block:: ruby

    Person.has_many :out, :posts, type: :wrote

  means that a `WROTE` relationship goes from a `Person` node to a `Post` node

**name:**
  The name of the association.  The affects the methods which are created (see above).
  The name is also used to form default assumptions about the model which is being referred to

  Example:

  .. code-block:: ruby

    Person.has_many :out, :posts, type: :wrote

  will assume a `model_class` option of ``'Post'`` unless otherwise specified

**options:** A ``Hash`` of options.  Allowed keys are:
  *type*: The Neo4j relationship type.  This option is required unless either the
    `origin` or `rel_class` options are specified

  *origin*: The name of the association from another model which the `type` and `model_class`
    can be gathered.

    Example:

    .. code-block:: ruby

      # `model_class` of `Post` is assumed here
      Person.has_many :out, :posts, origin: :author

      Post.has_one :in, :author, type: :has_author, model_class: :Person

  *model_class*: The model class to which the association is referring.  Can be a
    Symbol/String (or an ``Array`` of same) with the name of the `ActiveNode` class,
    `false` to specify any model, or nil to specify that it should be guessed.

  *rel_class*: The ``ActiveRel`` class to use for this association.  Can be either a
    model object ``include`` ing ``ActiveRel`` or a Symbol/String (or an ``Array`` of same).
    **A Symbol or String is recommended** to avoid load-time issues

  *dependent*: Enables deletion cascading.
    **Available values:** ``:delete``, ``:delete_orphans``, ``:destroy``, ``:destroy_orphans``
    (note that the ``:destroy_orphans`` option is known to be "very metal".  Caution advised)
    # File lib/neo4j/active_node/has_n.rb
330 def has_many(direction, name, options = {}) # rubocop:disable Style/PredicateName
331   name = name.to_sym
332   build_association(:has_many, direction, name, options)
333 
334   define_has_many_methods(name)
335 end
has_one(direction, name, options = {}) click to toggle source

For defining an “has one” association on a model. This defines a set of methods on your model instances. For instance, if you define the association on a Person model:

has_one :out, :vehicle, type: :has_vehicle

This would define the methods: “#vehicle“, “#vehicle=“, and “.vehicle“.

See :ref:‘#has_many <Neo4j/ActiveNode/HasN/ClassMethods#has_many>` for anything not specified here

    # File lib/neo4j/active_node/has_n.rb
347 def has_one(direction, name, options = {}) # rubocop:disable Style/PredicateName
348   name = name.to_sym
349   build_association(:has_one, direction, name, options)
350 
351   define_has_one_methods(name)
352 end
inherited(klass) click to toggle source

make sure the inherited classes inherit the _decl_rels hash

Calls superclass method
    # File lib/neo4j/active_node/has_n.rb
241 def inherited(klass)
242   klass.instance_variable_set(:@associations, associations.clone)
243   @associations_keys = klass.associations_keys.clone
244   super
245 end

Private Instance Methods

association_proxy(name, options = {}) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
490 def association_proxy(name, options = {})
491   AssociationProxy.new(association_query_proxy(name, options))
492 end
association_query_proxy(name, options = {}) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
474 def association_query_proxy(name, options = {})
475   previous_query_proxy = options[:previous_query_proxy] || current_scope
476   query_proxy = previous_query_proxy || default_association_query_proxy
477   Neo4j::ActiveNode::Query::QueryProxy.new(association_target_class(name),
478                                            associations[name],
479                                            {session: neo4j_session,
480                                             query_proxy: query_proxy,
481                                             context: "#{query_proxy.context || self.name}##{name}",
482                                             optional: query_proxy.optional?,
483                                             association_labels: options[:labels],
484                                             source_object: query_proxy.source_object}.merge!(options)).tap do |query_proxy_result|
485                                               target_classes = association_target_classes(name)
486                                               return query_proxy_result.as_models(target_classes) if target_classes
487                                             end
488 end
association_target_class(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
494 def association_target_class(name)
495   target_classes_or_nil = associations[name].target_classes_or_nil
496 
497   return if !target_classes_or_nil.is_a?(Array) || target_classes_or_nil.size != 1
498 
499   target_classes_or_nil[0]
500 end
association_target_classes(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
502 def association_target_classes(name)
503   target_classes_or_nil = associations[name].target_classes_or_nil
504 
505   return if !target_classes_or_nil.is_a?(Array) || target_classes_or_nil.size <= 1
506 
507   target_classes_or_nil
508 end
build_association(macro, direction, name, options) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
515 def build_association(macro, direction, name, options)
516   options[:model_class] = options[:model_class].name if options[:model_class] == self
517   Neo4j::ActiveNode::HasN::Association.new(macro, direction, name, options).tap do |association|
518     @associations ||= {}
519     @associations[name] = association
520     create_reflection(macro, name, association, self)
521   end
522 
523   associations_keys << name
524 
525 # Re-raise any exception with added class name and association name to
526 # make sure error message is helpful
527 rescue StandardError => e
528   raise e.class, "#{e.message} (#{self.class}##{name})"
529 end
default_association_query_proxy() click to toggle source
    # File lib/neo4j/active_node/has_n.rb
510 def default_association_query_proxy
511   Neo4j::ActiveNode::Query::QueryProxy.new("::#{self.name}".constantize, nil,
512                                            session: neo4j_session, query_proxy: nil, context: "#{self.name}")
513 end
define_class_method(*args, &block) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
467 def define_class_method(*args, &block)
468   klass = class << self; self; end
469   klass.instance_eval do
470     define_method(*args, &block)
471   end
472 end
define_has_many_id_methods(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
386 def define_has_many_id_methods(name)
387   define_method_unless_defined("#{name.to_s.singularize}_ids") do
388     association_proxy(name).result_ids
389   end
390 
391   define_method_unless_defined("#{name.to_s.singularize}_ids=") do |ids|
392     clear_deferred_nodes_for_association(name)
393     association_proxy(name).replace_with(ids)
394   end
395 
396   define_method_unless_defined("#{name.to_s.singularize}_neo_ids") do
397     association_proxy(name).pluck(:neo_id)
398   end
399 end
define_has_many_methods(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
356 def define_has_many_methods(name)
357   define_method(name) do |node = nil, rel = nil, options = {}|
358     # return [].freeze unless self._persisted_obj
359 
360     options, node = node, nil if node.is_a?(Hash)
361 
362     association_proxy(name, {node: node, rel: rel, source_object: self, labels: options[:labels]}.merge!(options))
363   end
364 
365   define_has_many_setter(name)
366 
367   define_has_many_id_methods(name)
368 
369   define_class_method(name) do |node = nil, rel = nil, options = {}|
370     options, node = node, nil if node.is_a?(Hash)
371 
372     association_proxy(name, {node: node, rel: rel, labels: options[:labels]}.merge!(options))
373   end
374 end
define_has_many_setter(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
376 def define_has_many_setter(name)
377   define_method("#{name}=") do |other_nodes|
378     association_proxy_cache.clear
379 
380     clear_deferred_nodes_for_association(name)
381 
382     Neo4j::Transaction.run { association_proxy(name).replace_with(other_nodes) }
383   end
384 end
define_has_one_getter(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
433 def define_has_one_getter(name)
434   define_method(name) do |node = nil, rel = nil, options = {}|
435     options, node = node, nil if node.is_a?(Hash)
436 
437     # Return all results if a variable-length relationship length was given
438     association_proxy = association_proxy(name, {node: node, rel: rel}.merge!(options))
439     if options[:rel_length] && !options[:rel_length].is_a?(Fixnum)
440       association_proxy
441     else
442       target_class = self.class.send(:association_target_class, name)
443       o = association_proxy.result.first
444       if target_class
445         target_class.send(:nodeify, o)
446       else
447         o
448       end
449     end
450   end
451 end
define_has_one_id_methods(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
419 def define_has_one_id_methods(name)
420   define_method_unless_defined("#{name}_id") do
421     association_proxy(name).result_ids.first
422   end
423 
424   define_method_unless_defined("#{name}_id=") do |id|
425     association_proxy(name).replace_with(id)
426   end
427 
428   define_method_unless_defined("#{name}_neo_id") do
429     association_proxy(name).pluck(:neo_id).first
430   end
431 end
define_has_one_methods(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
405 def define_has_one_methods(name)
406   define_has_one_getter(name)
407 
408   define_has_one_setter(name)
409 
410   define_has_one_id_methods(name)
411 
412   define_class_method(name) do |node = nil, rel = nil, options = {}|
413     options, node = node, nil if node.is_a?(Hash)
414 
415     association_proxy(name, {node: node, rel: rel, labels: options[:labels]}.merge!(options))
416   end
417 end
define_has_one_setter(name) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
453 def define_has_one_setter(name)
454   define_method("#{name}=") do |other_node|
455     if persisted?
456       other_node.save if other_node.respond_to?(:persisted?) && !other_node.persisted?
457       association_proxy_cache.clear # TODO: Should probably just clear for this association...
458       Neo4j::Transaction.run { association_proxy(name).replace_with(other_node) }
459       # handle_non_persisted_node(other_node)
460     else
461       defer_create(name, other_node, clear: true)
462       other_node
463     end
464   end
465 end
define_method_unless_defined(method_name, &block) click to toggle source
    # File lib/neo4j/active_node/has_n.rb
401 def define_method_unless_defined(method_name, &block)
402   define_method(method_name, block) unless method_defined?(method_name)
403 end