module ActiveGraph::Node::HasN::ClassMethods
rubocop:disable Metrics/ModuleLength
Public Instance Methods
association?(name)
click to toggle source
rubocop:enable Naming/PredicateName
# File lib/active_graph/node/has_n.rb 292 def association?(name) 293 !!associations[name.to_sym] 294 end
associations()
click to toggle source
# File lib/active_graph/node/has_n.rb 300 def associations 301 (@associations ||= parent_associations.dup) 302 end
associations_keys()
click to toggle source
# File lib/active_graph/node/has_n.rb 304 def associations_keys 305 @associations_keys ||= associations.keys 306 end
has_association?(name)
click to toggle source
:nocov:
# File lib/active_graph/node/has_n.rb 283 def has_association?(name) 284 ActiveSupport::Deprecation.warn 'has_association? is deprecated and may be removed from future releases, use association? instead.', caller 285 286 association?(name) 287 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 `Node` class, `false` to specify any model, or nil to specify that it should be guessed. *rel_class*: The ``Relationship`` class to use for this association. Can be either a model object ``include`` ing ``Relationship`` 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/active_graph/node/has_n.rb 391 def has_many(direction, name, options = {}) # rubocop:disable Naming/PredicateName 392 name = name.to_sym 393 build_association(:has_many, direction, name, options) 394 395 define_has_many_methods(name, options) 396 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 <ActiveGraph/Node/HasN/ClassMethods#has_many>` for anything not specified here
# File lib/active_graph/node/has_n.rb 408 def has_one(direction, name, options = {}) # rubocop:disable Naming/PredicateName 409 name = name.to_sym 410 build_association(:has_one, direction, name, options) 411 412 define_has_one_methods(name, options) 413 end
parent_associations()
click to toggle source
# File lib/active_graph/node/has_n.rb 296 def parent_associations 297 superclass == Object ? {} : superclass.associations 298 end
Private Instance Methods
add_association(name, association_object)
click to toggle source
# File lib/active_graph/node/has_n.rb 590 def add_association(name, association_object) 591 fail "Association `#{name}` defined for a second time. "\ 592 'Associations can only be defined once' if duplicate_association?(name) 593 associations[name] = association_object 594 end
association_proxy(name, options = {})
click to toggle source
# File lib/active_graph/node/has_n.rb 550 def association_proxy(name, options = {}) 551 AssociationProxy.new(association_query_proxy(name, options)) 552 end
association_query_proxy(name, options = {})
click to toggle source
# File lib/active_graph/node/has_n.rb 535 def association_query_proxy(name, options = {}) 536 previous_query_proxy = options[:previous_query_proxy] || current_scope 537 query_proxy = previous_query_proxy || default_association_query_proxy 538 ActiveGraph::Node::Query::QueryProxy.new(association_target_class(name), 539 associations[name], 540 {query_proxy: query_proxy, 541 context: "#{query_proxy.context || self.name}##{name}", 542 optional: query_proxy.optional?, 543 association_labels: options[:labels], 544 source_object: query_proxy.source_object}.merge!(options)).tap do |query_proxy_result| 545 target_classes = association_target_classes(name) 546 return query_proxy_result.as_models(target_classes) if target_classes 547 end 548 end
association_target_class(name)
click to toggle source
# File lib/active_graph/node/has_n.rb 554 def association_target_class(name) 555 target_classes_or_nil = associations[name].target_classes_or_nil 556 557 return if !target_classes_or_nil.is_a?(Array) || target_classes_or_nil.size != 1 558 559 target_classes_or_nil[0] 560 end
association_target_classes(name)
click to toggle source
# File lib/active_graph/node/has_n.rb 562 def association_target_classes(name) 563 target_classes_or_nil = associations[name].target_classes_or_nil 564 565 return if !target_classes_or_nil.is_a?(Array) || target_classes_or_nil.size <= 1 566 567 target_classes_or_nil 568 end
build_association(macro, direction, name, options)
click to toggle source
# File lib/active_graph/node/has_n.rb 575 def build_association(macro, direction, name, options) 576 options[:model_class] = options[:model_class].name if options[:model_class] == self 577 ActiveGraph::Node::HasN::Association.new(macro, direction, name, options).tap do |association| 578 add_association(name, association) 579 create_reflection(macro, name, association, self) 580 end 581 582 @associations_keys = nil 583 584 # Re-raise any exception with added class name and association name to 585 # make sure error message is helpful 586 rescue StandardError => e 587 raise e.class, "#{e.message} (#{self.class}##{name})" 588 end
default_association_query_proxy()
click to toggle source
# File lib/active_graph/node/has_n.rb 570 def default_association_query_proxy 571 ActiveGraph::Node::Query::QueryProxy.new("::#{self.name}".constantize, nil, 572 query_proxy: nil, context: self.name.to_s) 573 end
define_class_method(*args, &block)
click to toggle source
# File lib/active_graph/node/has_n.rb 528 def define_class_method(*args, &block) 529 klass = class << self; self; end 530 klass.instance_eval do 531 define_method(*args, &block) 532 end 533 end
define_has_many_id_methods(name)
click to toggle source
# File lib/active_graph/node/has_n.rb 447 def define_has_many_id_methods(name) 448 define_method_unless_defined("#{name.to_s.singularize}_ids") do 449 association_proxy(name).result_ids 450 end 451 452 define_setter(name, "#{name.to_s.singularize}_ids=") 453 454 define_method_unless_defined("#{name.to_s.singularize}_neo_ids") do 455 association_proxy(name).pluck(:neo_id) 456 end 457 end
define_has_many_methods(name, association_options)
click to toggle source
# File lib/active_graph/node/has_n.rb 417 def define_has_many_methods(name, association_options) 418 default_options = association_options.slice(:labels) 419 420 define_method(name) do |node = nil, rel = nil, options = {}| 421 # return [].freeze unless self._persisted_obj 422 423 options, node = node, nil if node.is_a?(Hash) 424 425 options = default_options.merge(options) 426 427 association_proxy(name, {node: node, rel: rel, source_object: self, labels: options[:labels]}.merge!(options)) 428 end 429 430 define_has_many_setter(name) 431 432 define_has_many_id_methods(name) 433 434 define_class_method(name) do |node = nil, rel = nil, options = {}| 435 options, node = node, nil if node.is_a?(Hash) 436 437 options = default_options.merge(options) 438 439 association_proxy(name, {node: node, rel: rel, labels: options[:labels]}.merge!(options)) 440 end 441 end
define_has_many_setter(name)
click to toggle source
# File lib/active_graph/node/has_n.rb 443 def define_has_many_setter(name) 444 define_setter(name, "#{name}=") 445 end
define_has_one_getter(name, default_options)
click to toggle source
# File lib/active_graph/node/has_n.rb 506 def define_has_one_getter(name, default_options) 507 define_method(name) do |node = nil, rel = nil, options = {}| 508 options, node = node, nil if node.is_a?(Hash) 509 510 options = default_options.merge(options) 511 512 association_proxy = association_proxy(name, {node: node, rel: rel}.merge!(options)) 513 514 # Return all results if options[:chainable] == true or a variable-length relationship length was given 515 if options[:chainable] || (options[:rel_length] && !options[:rel_length].is_a?(Integer)) 516 association_proxy 517 else 518 o = association_proxy.result.first 519 self.class.send(:association_target_class, name).try(:nodeify, o) || o 520 end 521 end 522 end
define_has_one_id_methods(name)
click to toggle source
# File lib/active_graph/node/has_n.rb 494 def define_has_one_id_methods(name) 495 define_method_unless_defined("#{name}_id") do 496 association_proxy(name).result_ids.first 497 end 498 499 define_setter(name, "#{name}_id=") 500 501 define_method_unless_defined("#{name}_neo_id") do 502 association_proxy(name).pluck(:neo_id).first 503 end 504 end
define_has_one_methods(name, association_options)
click to toggle source
# File lib/active_graph/node/has_n.rb 476 def define_has_one_methods(name, association_options) 477 default_options = association_options.slice(:labels) 478 479 define_has_one_getter(name, default_options) 480 481 define_has_one_setter(name) 482 483 define_has_one_id_methods(name) 484 485 define_class_method(name) do |node = nil, rel = nil, options = {}| 486 options, node = node, nil if node.is_a?(Hash) 487 488 options = default_options.merge(options) 489 490 association_proxy(name, {node: node, rel: rel, labels: options[:labels]}.merge!(options)) 491 end 492 end
define_has_one_setter(name)
click to toggle source
# File lib/active_graph/node/has_n.rb 524 def define_has_one_setter(name) 525 define_setter(name, "#{name}=") 526 end
define_method_unless_defined(method_name, &block)
click to toggle source
# File lib/active_graph/node/has_n.rb 472 def define_method_unless_defined(method_name, &block) 473 define_method(method_name, block) unless method_defined?(method_name) 474 end
define_setter(name, setter_name)
click to toggle source
# File lib/active_graph/node/has_n.rb 459 def define_setter(name, setter_name) 460 define_method_unless_defined(setter_name) do |others| 461 association_proxy_cache.clear # TODO: Should probably just clear for this association... 462 clear_deferred_nodes_for_association(name) 463 others = Array(others).reject(&:blank?) 464 if persisted? 465 ActiveGraph::Base.transaction { association_proxy(name).replace_with(others) } 466 else 467 defer_create(name, others, clear: true) 468 end 469 end 470 end
duplicate_association?(name)
click to toggle source
# File lib/active_graph/node/has_n.rb 596 def duplicate_association?(name) 597 associations.key?(name) && parent_associations[name] != associations[name] 598 end