activegraph 11.0.0.beta.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2016 -0
  3. data/CONTRIBUTORS +12 -0
  4. data/Gemfile +24 -0
  5. data/README.md +111 -0
  6. data/activegraph.gemspec +52 -0
  7. data/bin/rake +17 -0
  8. data/config/locales/en.yml +5 -0
  9. data/config/neo4j/add_classnames.yml +1 -0
  10. data/config/neo4j/config.yml +35 -0
  11. data/lib/active_graph.rb +123 -0
  12. data/lib/active_graph/ansi.rb +14 -0
  13. data/lib/active_graph/attribute_set.rb +32 -0
  14. data/lib/active_graph/base.rb +77 -0
  15. data/lib/active_graph/class_arguments.rb +39 -0
  16. data/lib/active_graph/config.rb +135 -0
  17. data/lib/active_graph/core.rb +14 -0
  18. data/lib/active_graph/core/connection_failed_error.rb +6 -0
  19. data/lib/active_graph/core/cypher_error.rb +37 -0
  20. data/lib/active_graph/core/entity.rb +11 -0
  21. data/lib/active_graph/core/instrumentable.rb +37 -0
  22. data/lib/active_graph/core/label.rb +135 -0
  23. data/lib/active_graph/core/logging.rb +44 -0
  24. data/lib/active_graph/core/node.rb +15 -0
  25. data/lib/active_graph/core/querable.rb +41 -0
  26. data/lib/active_graph/core/query.rb +485 -0
  27. data/lib/active_graph/core/query_builder.rb +18 -0
  28. data/lib/active_graph/core/query_clauses.rb +727 -0
  29. data/lib/active_graph/core/query_ext.rb +24 -0
  30. data/lib/active_graph/core/query_find_in_batches.rb +46 -0
  31. data/lib/active_graph/core/record.rb +51 -0
  32. data/lib/active_graph/core/result.rb +31 -0
  33. data/lib/active_graph/core/schema.rb +65 -0
  34. data/lib/active_graph/core/schema_errors.rb +12 -0
  35. data/lib/active_graph/core/wrappable.rb +30 -0
  36. data/lib/active_graph/errors.rb +59 -0
  37. data/lib/active_graph/lazy_attribute_hash.rb +38 -0
  38. data/lib/active_graph/migration.rb +148 -0
  39. data/lib/active_graph/migrations.rb +27 -0
  40. data/lib/active_graph/migrations/base.rb +77 -0
  41. data/lib/active_graph/migrations/check_pending.rb +20 -0
  42. data/lib/active_graph/migrations/helpers.rb +105 -0
  43. data/lib/active_graph/migrations/helpers/id_property.rb +72 -0
  44. data/lib/active_graph/migrations/helpers/relationships.rb +66 -0
  45. data/lib/active_graph/migrations/helpers/schema.rb +63 -0
  46. data/lib/active_graph/migrations/migration_file.rb +24 -0
  47. data/lib/active_graph/migrations/runner.rb +195 -0
  48. data/lib/active_graph/migrations/schema.rb +64 -0
  49. data/lib/active_graph/migrations/schema_migration.rb +14 -0
  50. data/lib/active_graph/model_schema.rb +139 -0
  51. data/lib/active_graph/node.rb +110 -0
  52. data/lib/active_graph/node/callbacks.rb +8 -0
  53. data/lib/active_graph/node/dependent.rb +11 -0
  54. data/lib/active_graph/node/dependent/association_methods.rb +49 -0
  55. data/lib/active_graph/node/dependent/query_proxy_methods.rb +52 -0
  56. data/lib/active_graph/node/dependent_callbacks.rb +31 -0
  57. data/lib/active_graph/node/enum.rb +26 -0
  58. data/lib/active_graph/node/has_n.rb +602 -0
  59. data/lib/active_graph/node/has_n/association.rb +278 -0
  60. data/lib/active_graph/node/has_n/association/rel_factory.rb +61 -0
  61. data/lib/active_graph/node/has_n/association/rel_wrapper.rb +23 -0
  62. data/lib/active_graph/node/has_n/association_cypher_methods.rb +108 -0
  63. data/lib/active_graph/node/id_property.rb +224 -0
  64. data/lib/active_graph/node/id_property/accessor.rb +62 -0
  65. data/lib/active_graph/node/initialize.rb +21 -0
  66. data/lib/active_graph/node/labels.rb +207 -0
  67. data/lib/active_graph/node/labels/index.rb +37 -0
  68. data/lib/active_graph/node/labels/reloading.rb +21 -0
  69. data/lib/active_graph/node/node_list_formatter.rb +13 -0
  70. data/lib/active_graph/node/node_wrapper.rb +54 -0
  71. data/lib/active_graph/node/orm_adapter.rb +82 -0
  72. data/lib/active_graph/node/persistence.rb +186 -0
  73. data/lib/active_graph/node/property.rb +60 -0
  74. data/lib/active_graph/node/query.rb +76 -0
  75. data/lib/active_graph/node/query/query_proxy.rb +367 -0
  76. data/lib/active_graph/node/query/query_proxy_eager_loading.rb +177 -0
  77. data/lib/active_graph/node/query/query_proxy_eager_loading/association_tree.rb +75 -0
  78. data/lib/active_graph/node/query/query_proxy_enumerable.rb +110 -0
  79. data/lib/active_graph/node/query/query_proxy_find_in_batches.rb +19 -0
  80. data/lib/active_graph/node/query/query_proxy_link.rb +139 -0
  81. data/lib/active_graph/node/query/query_proxy_methods.rb +303 -0
  82. data/lib/active_graph/node/query/query_proxy_methods_of_mass_updating.rb +99 -0
  83. data/lib/active_graph/node/query_methods.rb +68 -0
  84. data/lib/active_graph/node/reflection.rb +86 -0
  85. data/lib/active_graph/node/rels.rb +11 -0
  86. data/lib/active_graph/node/scope.rb +166 -0
  87. data/lib/active_graph/node/unpersisted.rb +48 -0
  88. data/lib/active_graph/node/validations.rb +59 -0
  89. data/lib/active_graph/paginated.rb +27 -0
  90. data/lib/active_graph/railtie.rb +108 -0
  91. data/lib/active_graph/relationship.rb +68 -0
  92. data/lib/active_graph/relationship/callbacks.rb +21 -0
  93. data/lib/active_graph/relationship/initialize.rb +28 -0
  94. data/lib/active_graph/relationship/persistence.rb +133 -0
  95. data/lib/active_graph/relationship/persistence/query_factory.rb +95 -0
  96. data/lib/active_graph/relationship/property.rb +92 -0
  97. data/lib/active_graph/relationship/query.rb +99 -0
  98. data/lib/active_graph/relationship/rel_wrapper.rb +31 -0
  99. data/lib/active_graph/relationship/related_node.rb +87 -0
  100. data/lib/active_graph/relationship/types.rb +80 -0
  101. data/lib/active_graph/relationship/validations.rb +8 -0
  102. data/lib/active_graph/schema/operation.rb +102 -0
  103. data/lib/active_graph/shared.rb +48 -0
  104. data/lib/active_graph/shared/attributes.rb +217 -0
  105. data/lib/active_graph/shared/callbacks.rb +66 -0
  106. data/lib/active_graph/shared/cypher.rb +37 -0
  107. data/lib/active_graph/shared/declared_properties.rb +204 -0
  108. data/lib/active_graph/shared/declared_property.rb +109 -0
  109. data/lib/active_graph/shared/declared_property/index.rb +37 -0
  110. data/lib/active_graph/shared/enum.rb +167 -0
  111. data/lib/active_graph/shared/filtered_hash.rb +79 -0
  112. data/lib/active_graph/shared/identity.rb +34 -0
  113. data/lib/active_graph/shared/initialize.rb +65 -0
  114. data/lib/active_graph/shared/marshal.rb +23 -0
  115. data/lib/active_graph/shared/mass_assignment.rb +63 -0
  116. data/lib/active_graph/shared/permitted_attributes.rb +28 -0
  117. data/lib/active_graph/shared/persistence.rb +272 -0
  118. data/lib/active_graph/shared/property.rb +249 -0
  119. data/lib/active_graph/shared/query_factory.rb +122 -0
  120. data/lib/active_graph/shared/rel_type_converters.rb +43 -0
  121. data/lib/active_graph/shared/serialized_properties.rb +30 -0
  122. data/lib/active_graph/shared/type_converters.rb +439 -0
  123. data/lib/active_graph/shared/typecasted_attributes.rb +99 -0
  124. data/lib/active_graph/shared/typecaster.rb +53 -0
  125. data/lib/active_graph/shared/validations.rb +44 -0
  126. data/lib/active_graph/tasks/migration.rake +204 -0
  127. data/lib/active_graph/timestamps.rb +11 -0
  128. data/lib/active_graph/timestamps/created.rb +9 -0
  129. data/lib/active_graph/timestamps/updated.rb +9 -0
  130. data/lib/active_graph/transaction.rb +22 -0
  131. data/lib/active_graph/transactions.rb +57 -0
  132. data/lib/active_graph/type_converters.rb +7 -0
  133. data/lib/active_graph/undeclared_properties.rb +53 -0
  134. data/lib/active_graph/version.rb +3 -0
  135. data/lib/active_graph/wrapper.rb +4 -0
  136. data/lib/rails/generators/active_graph/migration/migration_generator.rb +16 -0
  137. data/lib/rails/generators/active_graph/migration/templates/migration.erb +9 -0
  138. data/lib/rails/generators/active_graph/model/model_generator.rb +89 -0
  139. data/lib/rails/generators/active_graph/model/templates/migration.erb +11 -0
  140. data/lib/rails/generators/active_graph/model/templates/model.erb +15 -0
  141. data/lib/rails/generators/active_graph/upgrade_v8/templates/migration.erb +17 -0
  142. data/lib/rails/generators/active_graph/upgrade_v8/upgrade_v8_generator.rb +34 -0
  143. data/lib/rails/generators/active_graph_generator.rb +121 -0
  144. metadata +423 -0
@@ -0,0 +1,59 @@
1
+ module ActiveGraph
2
+ module Node
3
+ # This mixin replace the original save method and performs validation before the save.
4
+ module Validations
5
+ extend ActiveSupport::Concern
6
+ include ActiveGraph::Shared::Validations
7
+
8
+
9
+ # @return [Boolean] true if valid
10
+ def valid?(context = nil)
11
+ context ||= (new_record? ? :create : :update)
12
+ super(context)
13
+ errors.empty?
14
+ end
15
+
16
+ module ClassMethods
17
+ def validates_uniqueness_of(*attr_names)
18
+ validates_with UniquenessValidator, _merge_attributes(attr_names)
19
+ end
20
+ end
21
+
22
+
23
+ class UniquenessValidator < ::ActiveModel::EachValidator
24
+ def initialize(options)
25
+ super(options.reverse_merge(case_sensitive: true))
26
+ end
27
+
28
+ def validate_each(record, attribute, value)
29
+ return unless found(record, attribute, value).exists?
30
+
31
+ record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(value: value))
32
+ end
33
+
34
+ def found(record, attribute, value)
35
+ conditions = scope_conditions(record)
36
+
37
+ # TODO: Added as find(:name => nil) throws error
38
+ value = '' if value.nil?
39
+
40
+ conditions[attribute] = options[:case_sensitive] ? value : /#{Regexp.escape(value.to_s)}/i
41
+
42
+ found = record.class.as(:result).where(conditions)
43
+ found = found.where_not(neo_id: record.neo_id) if record._persisted_obj
44
+ found
45
+ end
46
+
47
+ def message(instance)
48
+ super || 'has already been taken'
49
+ end
50
+
51
+ def scope_conditions(instance)
52
+ Array(options[:scope] || []).inject({}) do |conditions, key|
53
+ conditions.merge(key => instance[key])
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,27 @@
1
+ module ActiveGraph
2
+ class Paginated
3
+ include Enumerable
4
+ attr_reader :items, :total, :current_page
5
+
6
+ def initialize(items, total, current_page)
7
+ @items = items
8
+ @total = total
9
+ @current_page = current_page
10
+ end
11
+
12
+ def self.create_from(source, page, per_page, order = nil)
13
+ target = source.node_var || source.identity
14
+ partial = source.skip((page - 1) * per_page).limit(per_page)
15
+ ordered_partial, ordered_source = if order
16
+ [partial.order_by(order), source.query.with("#{target} as #{target}").pluck("COUNT(#{target})").first]
17
+ else
18
+ [partial, source.count]
19
+ end
20
+ Paginated.new(ordered_partial, ordered_source, page)
21
+ end
22
+
23
+ delegate :each, to: :items
24
+ delegate :pluck, to: :items
25
+ delegate :size, :[], to: :items
26
+ end
27
+ end
@@ -0,0 +1,108 @@
1
+ require 'active_support/notifications'
2
+ require 'rails/railtie'
3
+ # Need the action_dispatch railtie to have action_dispatch.rescue_responses initialized correctly
4
+ require 'action_dispatch/railtie'
5
+ require 'active_graph'
6
+
7
+ module ActiveGraph
8
+ class Railtie < ::Rails::Railtie
9
+ def empty_config
10
+ ActiveSupport::OrderedOptions.new.tap do |cfg|
11
+ cfg.driver = ActiveSupport::OrderedOptions.new
12
+ end
13
+ end
14
+
15
+ config.neo4j = empty_config
16
+
17
+ if defined?(ActiveSupport::Reloader)
18
+ ActiveSupport::Reloader.to_prepare do
19
+ ActiveGraph::Node::Labels::Reloading.reload_models!
20
+ end
21
+ elsif const_defined?(:ActionDispatch)
22
+ ActionDispatch::Reloader.to_prepare do
23
+ ActiveGraph::Node::Labels::Reloading.reload_models!
24
+ end
25
+ end
26
+
27
+ # Rescue responses similar to ActiveRecord.
28
+ config.action_dispatch.rescue_responses.merge!(
29
+ 'ActiveGraph::RecordNotFound' => :not_found,
30
+ 'ActiveGraph::Node::Labels::RecordNotFound' => :not_found
31
+ )
32
+
33
+ # Add ActiveModel translations to the I18n load_path
34
+ initializer 'i18n' do
35
+ config.i18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', '..', '..', 'config', 'locales', '*.{rb,yml}')]
36
+ end
37
+
38
+ console do
39
+ ActiveGraph::Config[:logger] = ActiveSupport::Logger.new(STDOUT)
40
+ ActiveGraph::Config[:verbose_query_logs] = false
41
+ end
42
+
43
+ # Starting Neo after :load_config_initializers allows apps to
44
+ # register migrations in config/initializers
45
+ initializer 'neo4j.start', after: :load_config_initializers do |app|
46
+ app.config.neo4j.skip_migration_check = true if Rails.env.test?
47
+
48
+ neo4j_config = ActiveSupport::OrderedOptions.new
49
+ app.config.neo4j.each { |k, v| neo4j_config[k] = v } if app.config.neo4j
50
+
51
+ ActiveGraph::Config.configuration.merge!(neo4j_config.to_h)
52
+
53
+ ActiveGraph::Base.on_establish_driver { setup! neo4j_config }
54
+
55
+ ActiveGraph::Config[:logger] ||= Rails.logger
56
+
57
+ if ActiveGraph::Config.fail_on_pending_migrations
58
+ config.app_middleware.insert_after ::ActionDispatch::Callbacks, ActiveGraph::Migrations::CheckPending
59
+ end
60
+ end
61
+
62
+ def setup!(config = empty_config)
63
+ config = final_driver_config!(config)
64
+ scheme = config.delete(:scheme) || 'bolt'
65
+ host = config.delete(:host) || 'localhost'
66
+ port = config.delete(:port) || 7687
67
+ url = config.delete(:url) || URI::Generic.build( scheme: scheme, host: host, port: port ).to_s
68
+ username = config.delete(:username)
69
+ password = config.delete(:password)
70
+ auth_token = config.delete(:auth_token)
71
+ auth_token ||= username ? Neo4j::Driver::AuthTokens.basic(username, password) : Neo4j::Driver::AuthTokens.none
72
+ register_neo4j_cypher_logging
73
+
74
+ method = url.is_a?(Enumerable) ? :routing_driver : :driver
75
+ Neo4j::Driver::GraphDatabase.send(method, url, auth_token, config)
76
+ end
77
+
78
+ def final_driver_config!(config)
79
+ { url: ENV['NEO4J_URL'] }.compact.merge(config[:driver]).merge(yaml_config_data)
80
+ end
81
+
82
+ def yaml_config_data
83
+ @yaml_config_data ||=
84
+ yaml_path ? YAML.load(ERB.new(yaml_path.read).result)[Rails.env].transform_keys!(&:to_sym) : {}
85
+ end
86
+
87
+ def yaml_path
88
+ return unless defined?(Rails)
89
+ @yaml_path ||= %w(config/neo4j.yml config/neo4j.yaml).map do |path|
90
+ Rails.root.join(path)
91
+ end.detect(&:exist?)
92
+ end
93
+
94
+ def register_neo4j_cypher_logging
95
+ return if @neo4j_cypher_logging_registered
96
+
97
+ ActiveGraph::Core::Query.pretty_cypher = ActiveGraph::Config[:pretty_logged_cypher_queries]
98
+
99
+ logger_proc = ->(message) do
100
+ (ActiveGraph::Config[:logger] ||= Rails.logger).debug message
101
+ end
102
+ ActiveGraph::Base.subscribe_to_query(&logger_proc)
103
+ ActiveGraph::Base.subscribe_to_request(&logger_proc)
104
+
105
+ @neo4j_cypher_logging_registered = true
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,68 @@
1
+ module ActiveGraph
2
+ # Makes Neo4j Relationships more or less act like ActiveRecord objects.
3
+ # See documentation at https://github.com/neo4jrb/neo4j/wiki/Neo4j%3A%3AActiveRel
4
+ module Relationship
5
+ extend ActiveSupport::Concern
6
+
7
+ MARSHAL_INSTANCE_VARIABLES = [:@attributes, :@type, :@_persisted_obj]
8
+
9
+ include ActiveGraph::Shared
10
+ include ActiveGraph::Relationship::Initialize
11
+ include ActiveGraph::Shared::Identity
12
+ include ActiveGraph::Shared::Marshal
13
+ include ActiveGraph::Shared::SerializedProperties
14
+ include ActiveGraph::Relationship::Property
15
+ include ActiveGraph::Relationship::Persistence
16
+ include ActiveGraph::Relationship::Validations
17
+ include ActiveGraph::Relationship::Callbacks
18
+ include ActiveGraph::Relationship::Query
19
+ include ActiveGraph::Relationship::Types
20
+ include ActiveGraph::Shared::Enum
21
+ include ActiveGraph::Shared::PermittedAttributes
22
+ include ActiveGraph::Transactions
23
+
24
+ class FrozenRelError < ActiveGraph::Error; end
25
+
26
+ def initialize(from_node = nil, to_node = nil, args = nil)
27
+ load_nodes(node_or_nil(from_node), node_or_nil(to_node))
28
+ resolved_args = hash_or_nil(from_node, args)
29
+ symbol_args = sanitize_input_parameters(resolved_args)
30
+ super(symbol_args)
31
+ end
32
+
33
+ def node_cypher_representation(node)
34
+ node_class = node.class
35
+ id_name = node_class.id_property_name
36
+ labels = ':' + node_class.mapped_label_names.join(':')
37
+
38
+ "(#{labels} {#{id_name}: #{node.id.inspect}})"
39
+ end
40
+
41
+ def neo4j_obj
42
+ _persisted_obj || fail('Tried to access native neo4j object on a non persisted object')
43
+ end
44
+
45
+ included do
46
+ include ActiveGraph::Timestamps if ActiveGraph::Config[:record_timestamps]
47
+
48
+ def self.inherited(other)
49
+ attributes.each_pair do |k, v|
50
+ other.inherit_property k.to_sym, v.clone, declared_properties[k].options
51
+ end
52
+ super
53
+ end
54
+ end
55
+
56
+ ActiveSupport.run_load_hooks(:relationship, self)
57
+
58
+ private
59
+
60
+ def node_or_nil(node)
61
+ node.is_a?(ActiveGraph::Node) || node.is_a?(Integer) ? node : nil
62
+ end
63
+
64
+ def hash_or_nil(node_or_hash, hash_or_nil)
65
+ hash_or_parameter?(node_or_hash) ? node_or_hash : hash_or_nil
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveGraph
2
+ module Relationship
3
+ module Callbacks #:nodoc:
4
+ extend ActiveSupport::Concern
5
+ include ActiveGraph::Shared::Callbacks
6
+
7
+ def save(*args)
8
+ unless _persisted_obj || (from_node.respond_to?(:neo_id) && to_node.respond_to?(:neo_id))
9
+ fail ActiveGraph::Relationship::Persistence::RelInvalidError, 'from_node and to_node must be node objects'
10
+ end
11
+ super(*args)
12
+ end
13
+
14
+ def destroy
15
+ to_node.callbacks_from_relationship(self, :in, from_node).try(:last)
16
+ from_node.callbacks_from_relationship(self, :out, to_node).try(:last)
17
+ super
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ module ActiveGraph::Relationship
2
+ module Initialize
3
+ extend ActiveSupport::Concern
4
+ include ActiveGraph::Shared::Initialize
5
+
6
+ # called when loading the rel from the database
7
+ # @param [ActiveGraph::Embedded::EmbeddedRelationship, Neo4j::Server::CypherRelationship] persisted_rel properties of this relationship
8
+ # @param [ActiveGraph::Relationship] from_node_id The neo_id of the starting node of this rel
9
+ # @param [ActiveGraph::Relationship] to_node_id The neo_id of the ending node of this rel
10
+ # @param [String] type the relationship type
11
+ def init_on_load(persisted_rel, from_node_id, to_node_id, type)
12
+ @type = type
13
+ @_persisted_obj = persisted_rel
14
+ changed_attributes_clear!
15
+ @attributes = convert_and_assign_attributes(persisted_rel.properties)
16
+ load_nodes(from_node_id, to_node_id)
17
+ end
18
+
19
+ def init_on_reload(unwrapped_reloaded)
20
+ @attributes = nil
21
+ init_on_load(unwrapped_reloaded,
22
+ unwrapped_reloaded.start_node_id,
23
+ unwrapped_reloaded.end_node_id,
24
+ unwrapped_reloaded.type)
25
+ self
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,133 @@
1
+ module ActiveGraph::Relationship
2
+ module Persistence
3
+ extend ActiveSupport::Concern
4
+ include ActiveGraph::Shared::Cypher::RelIdentifiers
5
+ include ActiveGraph::Shared::Persistence
6
+
7
+ class RelInvalidError < RuntimeError; end
8
+ class ModelClassInvalidError < RuntimeError; end
9
+ class RelCreateFailedError < RuntimeError; end
10
+
11
+ def from_node_identifier
12
+ @from_node_identifier || :from_node
13
+ end
14
+
15
+ def to_node_identifier
16
+ @to_node_identifier || :to_node
17
+ end
18
+
19
+ def from_node_identifier=(id)
20
+ @from_node_identifier = id.to_sym
21
+ end
22
+
23
+ def to_node_identifier=(id)
24
+ @to_node_identifier = id.to_sym
25
+ end
26
+
27
+ def cypher_identifier
28
+ @cypher_identifier || :rel
29
+ end
30
+
31
+ def save(*)
32
+ create_or_update
33
+ end
34
+
35
+ def save!(*args)
36
+ save(*args) or fail(RelInvalidError, inspect) # rubocop:disable Style/AndOr
37
+ end
38
+
39
+ # Increments concurrently a numeric attribute by a centain amount
40
+ # @param [Symbol, String] attribute name of the attribute to increment
41
+ # @param [Integer, Float] by amount to increment
42
+ def concurrent_increment!(attribute, by = 1)
43
+ increment_by_query! query_as(:r), attribute, by, :r
44
+ end
45
+
46
+ def create_model
47
+ validate_node_classes!
48
+ delete_has_one_rel
49
+ rel = _create_rel
50
+ return self unless rel.respond_to?(:properties)
51
+ init_on_load(rel, from_node, to_node, @type)
52
+ true
53
+ end
54
+
55
+ def delete_has_one_rel
56
+ to_node.delete_reverse_has_one_relationship(self, :in, from_node) if to_node.persisted?
57
+ from_node.delete_reverse_has_one_relationship(self, :out, to_node) if from_node.persisted?
58
+ end
59
+
60
+ def query_as(var)
61
+ # This should query based on the nodes, not the rel neo_id, I think
62
+ # Also, picky point: Should the var be `n`?
63
+ self.class.query_as(neo_id, var)
64
+ end
65
+
66
+ module ClassMethods
67
+ # Creates a new relationship between objects
68
+ # @param [Hash] args the properties the new relationship should have
69
+ def create(*args)
70
+ new(*args).tap(&:save)
71
+ end
72
+
73
+ # Same as #create, but raises an error if there is a problem during save.
74
+ def create!(*args)
75
+ new(*args).tap(&:save!)
76
+ end
77
+
78
+ def create_method
79
+ creates_unique? ? :create_unique : :create
80
+ end
81
+
82
+ def load_entity(id)
83
+ query_as(id).pluck(:r).first
84
+ end
85
+
86
+ def query_as(neo_id, var = :r)
87
+ ActiveGraph::Base.new_query.match("()-[#{var}]->()").where(var => {neo_id: neo_id})
88
+ end
89
+ end
90
+
91
+ def create_method
92
+ self.class.create_method
93
+ end
94
+
95
+ private
96
+
97
+ def destroy_query
98
+ query_as(:r).delete(:r)
99
+ end
100
+
101
+ def validate_node_classes!
102
+ [from_node, to_node].each do |node|
103
+ type = from_node == node ? :_from_class : :_to_class
104
+ type_class = self.class.send(type)
105
+
106
+ unless valid_type?(type_class, node)
107
+ fail ModelClassInvalidError, type_validation_error_message(node, type_class)
108
+ end
109
+ end
110
+ end
111
+
112
+ def valid_type?(type_object, node)
113
+ case type_object
114
+ when false, :any
115
+ true
116
+ when Array
117
+ type_object.any? { |c| valid_type?(c, node) }
118
+ else
119
+ node.class.mapped_label_names.include?(type_object.to_s.constantize.mapped_label_name)
120
+ end
121
+ end
122
+
123
+ def type_validation_error_message(node, type_class)
124
+ "Node class was #{node.class} (#{node.class.object_id}), expected #{type_class} (#{type_class.object_id})"
125
+ end
126
+
127
+ def _create_rel
128
+ factory = QueryFactory.new(from_node, to_node, self)
129
+ factory.build!
130
+ factory.unwrapped_rel
131
+ end
132
+ end
133
+ end