neo4j 1.0.0.beta.20 → 3.0.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +243 -0
- data/CONTRIBUTORS +12 -0
- data/Gemfile +10 -11
- data/README.md +23 -0
- data/bin/neo4j-jars +33 -0
- data/config/locales/en.yml +5 -0
- data/config/neo4j/config.yml +98 -0
- data/lib/neo4j.rb +28 -68
- data/lib/neo4j/active_node.rb +60 -0
- data/lib/neo4j/active_node/callbacks.rb +41 -0
- data/lib/neo4j/active_node/has_n.rb +138 -0
- data/lib/neo4j/active_node/has_n/decl_rel.rb +236 -0
- data/lib/neo4j/active_node/has_n/nodes.rb +82 -0
- data/lib/neo4j/active_node/identity.rb +28 -0
- data/lib/neo4j/active_node/initialize.rb +24 -0
- data/lib/neo4j/active_node/labels.rb +142 -0
- data/lib/neo4j/active_node/persistence.rb +193 -0
- data/lib/neo4j/active_node/property.rb +41 -0
- data/lib/neo4j/active_node/rels.rb +11 -0
- data/lib/neo4j/active_node/validations.rb +51 -0
- data/lib/neo4j/railtie.rb +40 -0
- data/lib/neo4j/version.rb +1 -1
- data/lib/neo4j/wrapper.rb +25 -0
- data/neo4j.gemspec +25 -15
- metadata +136 -149
- data/README.rdoc +0 -135
- data/lib/generators/neo4j.rb +0 -65
- data/lib/generators/neo4j/model/model_generator.rb +0 -39
- data/lib/generators/neo4j/model/templates/model.erb +0 -7
- data/lib/neo4j/config.rb +0 -153
- data/lib/neo4j/database.rb +0 -56
- data/lib/neo4j/equal.rb +0 -21
- data/lib/neo4j/event_handler.rb +0 -116
- data/lib/neo4j/index/class_methods.rb +0 -62
- data/lib/neo4j/index/index.rb +0 -33
- data/lib/neo4j/index/indexer.rb +0 -312
- data/lib/neo4j/index/indexer_registry.rb +0 -68
- data/lib/neo4j/index/lucene_query.rb +0 -191
- data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j/jars/lucene-core-3.0.2.jar +0 -0
- data/lib/neo4j/jars/neo4j-index-1.2-1.2.M03.jar +0 -0
- data/lib/neo4j/jars/neo4j-kernel-1.2-1.2.M03.jar +0 -0
- data/lib/neo4j/jars/neo4j-lucene-index-0.2-1.2.M03.jar +0 -0
- data/lib/neo4j/load.rb +0 -21
- data/lib/neo4j/mapping/class_methods/init_node.rb +0 -50
- data/lib/neo4j/mapping/class_methods/init_rel.rb +0 -35
- data/lib/neo4j/mapping/class_methods/property.rb +0 -80
- data/lib/neo4j/mapping/class_methods/relationship.rb +0 -90
- data/lib/neo4j/mapping/class_methods/root.rb +0 -31
- data/lib/neo4j/mapping/class_methods/rule.rb +0 -295
- data/lib/neo4j/mapping/decl_relationship_dsl.rb +0 -214
- data/lib/neo4j/mapping/has_n.rb +0 -83
- data/lib/neo4j/mapping/node_mixin.rb +0 -97
- data/lib/neo4j/mapping/relationship_mixin.rb +0 -117
- data/lib/neo4j/model.rb +0 -4
- data/lib/neo4j/neo4j.rb +0 -95
- data/lib/neo4j/node.rb +0 -131
- data/lib/neo4j/node_mixin.rb +0 -4
- data/lib/neo4j/node_relationship.rb +0 -149
- data/lib/neo4j/node_traverser.rb +0 -157
- data/lib/neo4j/property.rb +0 -111
- data/lib/neo4j/rails/finders.rb +0 -121
- data/lib/neo4j/rails/lucene_connection_closer.rb +0 -19
- data/lib/neo4j/rails/mapping/property.rb +0 -35
- data/lib/neo4j/rails/model.rb +0 -324
- data/lib/neo4j/rails/railtie.rb +0 -16
- data/lib/neo4j/rails/transaction.rb +0 -67
- data/lib/neo4j/rails/tx_methods.rb +0 -15
- data/lib/neo4j/rails/validations/non_nil.rb +0 -11
- data/lib/neo4j/rails/validations/uniqueness.rb +0 -31
- data/lib/neo4j/rails/value.rb +0 -124
- data/lib/neo4j/rails/value_properties.rb +0 -29
- data/lib/neo4j/relationship.rb +0 -169
- data/lib/neo4j/relationship_mixin.rb +0 -4
- data/lib/neo4j/relationship_traverser.rb +0 -92
- data/lib/neo4j/to_java.rb +0 -31
- data/lib/neo4j/transaction.rb +0 -68
- data/lib/neo4j/type_converters.rb +0 -98
data/lib/neo4j.rb
CHANGED
@@ -1,70 +1,30 @@
|
|
1
|
-
include Java
|
2
|
-
|
3
|
-
require 'enumerator'
|
4
|
-
require 'forwardable'
|
5
|
-
require 'time'
|
6
|
-
require 'date'
|
7
|
-
|
8
|
-
require 'neo4j/jars/neo4j-index-1.2-1.2.M03.jar'
|
9
|
-
require 'neo4j/jars/neo4j-kernel-1.2-1.2.M03.jar'
|
10
|
-
require 'neo4j/jars/neo4j-lucene-index-0.2-1.2.M03.jar'
|
11
|
-
require 'neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar'
|
12
|
-
require 'neo4j/jars/lucene-core-3.0.2.jar'
|
13
|
-
require 'neo4j/to_java'
|
14
1
|
require 'neo4j/version'
|
15
|
-
require 'neo4j/equal'
|
16
|
-
|
17
|
-
require 'neo4j/event_handler'
|
18
|
-
require 'neo4j/database'
|
19
|
-
require 'neo4j/neo4j'
|
20
|
-
|
21
|
-
require 'neo4j/index/index'
|
22
|
-
require 'neo4j/index/class_methods'
|
23
|
-
require 'neo4j/index/indexer_registry'
|
24
|
-
require 'neo4j/index/indexer'
|
25
|
-
require 'neo4j/index/lucene_query'
|
26
|
-
require 'neo4j/relationship_traverser'
|
27
|
-
require 'neo4j/node_traverser'
|
28
|
-
require 'neo4j/property'
|
29
|
-
require 'neo4j/transaction'
|
30
|
-
require 'neo4j/node_relationship'
|
31
|
-
require 'neo4j/load'
|
32
|
-
require 'neo4j/relationship'
|
33
|
-
require 'neo4j/node'
|
34
|
-
require 'neo4j/config'
|
35
|
-
require 'neo4j/type_converters'
|
36
|
-
require 'neo4j/mapping/class_methods/init_node'
|
37
|
-
require 'neo4j/mapping/class_methods/init_rel'
|
38
|
-
require 'neo4j/mapping/class_methods/root'
|
39
|
-
require 'neo4j/mapping/class_methods/property'
|
40
|
-
require 'neo4j/mapping/class_methods/relationship'
|
41
|
-
require 'neo4j/mapping/decl_relationship_dsl'
|
42
|
-
require 'neo4j/mapping/has_n'
|
43
|
-
require 'neo4j/mapping/node_mixin'
|
44
|
-
require 'neo4j/mapping/relationship_mixin'
|
45
|
-
require 'neo4j/node_mixin'
|
46
|
-
require 'neo4j/relationship_mixin'
|
47
|
-
require 'neo4j/mapping/class_methods/rule'
|
48
|
-
|
49
|
-
# rails
|
50
|
-
require 'rails/railtie'
|
51
|
-
require 'active_model'
|
52
|
-
require 'neo4j/rails/tx_methods'
|
53
|
-
require 'neo4j/rails/transaction'
|
54
|
-
require 'neo4j/rails/railtie'
|
55
|
-
require 'neo4j/rails/validations/uniqueness'
|
56
|
-
require 'neo4j/rails/validations/non_nil'
|
57
|
-
require 'neo4j/rails/finders'
|
58
|
-
require 'neo4j/rails/mapping/property'
|
59
|
-
require 'neo4j/rails/model'
|
60
|
-
require 'neo4j/rails/value_properties'
|
61
|
-
require 'neo4j/rails/value'
|
62
|
-
require 'neo4j/rails/lucene_connection_closer'
|
63
|
-
|
64
|
-
require 'neo4j/model'
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
# hmm, looks like Enumerator have been moved in some ruby versions
|
69
|
-
Enumerator = Enumerable::Enumerator unless defined? Enumerator
|
70
2
|
|
3
|
+
#require "delegate"
|
4
|
+
#require "time"
|
5
|
+
#require "set"
|
6
|
+
#
|
7
|
+
#require "active_support/core_ext"
|
8
|
+
#require "active_support/json"
|
9
|
+
#require "active_support/inflector"
|
10
|
+
#require "active_support/time_with_zone"
|
11
|
+
|
12
|
+
require "neo4j-core"
|
13
|
+
require "active_model"
|
14
|
+
require 'active_support/concern'
|
15
|
+
require 'active_support/core_ext/class/attribute.rb'
|
16
|
+
|
17
|
+
require 'active_attr'
|
18
|
+
require 'neo4j/wrapper'
|
19
|
+
require "neo4j/active_node/labels"
|
20
|
+
require 'neo4j/active_node/identity'
|
21
|
+
require 'neo4j/active_node/callbacks'
|
22
|
+
require 'neo4j/active_node/initialize'
|
23
|
+
require 'neo4j/active_node/property'
|
24
|
+
require 'neo4j/active_node/persistence'
|
25
|
+
require 'neo4j/active_node/validations'
|
26
|
+
require 'neo4j/active_node/rels'
|
27
|
+
require 'neo4j/active_node/has_n'
|
28
|
+
require 'neo4j/active_node/has_n/decl_rel'
|
29
|
+
require 'neo4j/active_node/has_n/nodes'
|
30
|
+
require 'neo4j/active_node'
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Neo4j
|
2
|
+
|
3
|
+
# Makes Neo4j nodes and relationships behave like active record objects.
|
4
|
+
# By including this module in your class it will create a mapping for the node to your ruby class
|
5
|
+
# by using a Neo4j Label with the same name as the class. When the node is loaded from the database it
|
6
|
+
# will check if there is a ruby class for the labels it has.
|
7
|
+
# If there Ruby class with the same name as the label then the Neo4j node will be wrapped
|
8
|
+
# in a new object of that class.
|
9
|
+
#
|
10
|
+
# = ClassMethods
|
11
|
+
# * {Neo4j::ActiveNode::Labels::ClassMethods} defines methods like: <tt>index</tt> and <tt>find</tt>
|
12
|
+
# * {Neo4j::ActiveNode::Persistence::ClassMethods} defines methods like: <tt>create</tt> and <tt>create!</tt>
|
13
|
+
# * {Neo4j::ActiveNode::Property::ClassMethods} defines methods like: <tt>property</tt>.
|
14
|
+
#
|
15
|
+
# @example Create a Ruby wrapper for a Neo4j Node
|
16
|
+
# class Company
|
17
|
+
# include Neo4j::ActiveNode
|
18
|
+
# property :name
|
19
|
+
# end
|
20
|
+
# company = Company.new
|
21
|
+
# company.name = 'My Company AB'
|
22
|
+
# Company.save
|
23
|
+
#
|
24
|
+
module ActiveNode
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
extend ActiveModel::Naming
|
27
|
+
|
28
|
+
include ActiveModel::Conversion
|
29
|
+
include ActiveModel::Serializers::Xml
|
30
|
+
include ActiveModel::Serializers::JSON
|
31
|
+
include Neo4j::ActiveNode::Initialize
|
32
|
+
include Neo4j::ActiveNode::Identity
|
33
|
+
include Neo4j::ActiveNode::Persistence
|
34
|
+
include Neo4j::ActiveNode::Property
|
35
|
+
include Neo4j::ActiveNode::Labels
|
36
|
+
include Neo4j::ActiveNode::Callbacks
|
37
|
+
include Neo4j::ActiveNode::Validations
|
38
|
+
include Neo4j::ActiveNode::Rels
|
39
|
+
include Neo4j::ActiveNode::HasN
|
40
|
+
|
41
|
+
def wrapper
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def neo4j_obj
|
46
|
+
_persisted_node || raise("Tried to access native neo4j object on a none persisted object")
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
included do
|
51
|
+
def self.inherited(other)
|
52
|
+
attributes.each_pair do |k,v|
|
53
|
+
other.attributes[k] = v
|
54
|
+
end
|
55
|
+
Neo4j::ActiveNode::Labels.add_wrapped_class(other)
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module ActiveNode
|
3
|
+
module Callbacks #:nodoc:
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
include ActiveModel::Callbacks
|
8
|
+
end
|
9
|
+
|
10
|
+
included do
|
11
|
+
include ActiveModel::Validations::Callbacks
|
12
|
+
|
13
|
+
define_model_callbacks :initialize, :find, :only => :after
|
14
|
+
define_model_callbacks :save, :create, :update, :destroy
|
15
|
+
end
|
16
|
+
|
17
|
+
def destroy #:nodoc:
|
18
|
+
run_callbacks(:destroy) { super }
|
19
|
+
end
|
20
|
+
|
21
|
+
def touch(*) #:nodoc:
|
22
|
+
run_callbacks(:touch) { super }
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def create_or_update #:nodoc:
|
28
|
+
run_callbacks(:save) { super }
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_model #:nodoc:
|
32
|
+
run_callbacks(:create) { super }
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_model(*) #:nodoc:
|
36
|
+
run_callbacks(:update) { super }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Neo4j::ActiveNode
|
2
|
+
module HasN
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def _decl_rels_for(rel_type)
|
6
|
+
self.class._decl_rels[rel_type]
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def _decl_rels
|
12
|
+
@_decl_rels ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# make sure the inherited classes inherit the <tt>_decl_rels</tt> hash
|
16
|
+
def inherited(klass)
|
17
|
+
copy = _decl_rels.clone
|
18
|
+
copy.each_pair { |k, v| copy[k] = v.inherit_new }
|
19
|
+
klass.instance_variable_set(:@_decl_rels, copy)
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Specifies a relationship between two node active node classes.
|
25
|
+
# Generates assignment and accessor methods for the given relationship.
|
26
|
+
# Both incoming and outgoing relationships can be declared, see {Neo4j::ActiveNode::HasN::DeclRel}
|
27
|
+
#
|
28
|
+
# @example has_n(:files)
|
29
|
+
#
|
30
|
+
# class FolderNode
|
31
|
+
# include Neo4j::ActiveNode
|
32
|
+
# has_n(:files)
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# folder = FolderNode.new
|
36
|
+
# folder.files << Neo4j::Node.new << Neo4j::Node.new
|
37
|
+
# folder.files.inject {...}
|
38
|
+
#
|
39
|
+
# FolderNode.files #=> 'files' the name of the relationship
|
40
|
+
#
|
41
|
+
# @example has_n(x).to(...)
|
42
|
+
#
|
43
|
+
# # You can declare which class it has relationship to.
|
44
|
+
# # The generated relationships will be prefixed with the name of that class.
|
45
|
+
# class FolderNode
|
46
|
+
# include Neo4j::ActiveNode
|
47
|
+
# has_n(:files).to(File)
|
48
|
+
# # Same as has_n(:files).to("File")
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# FolderNode.files #=> 'File#files' the name of the relationship
|
52
|
+
#
|
53
|
+
# @example has_n(x).from(class, has_n_name)
|
54
|
+
#
|
55
|
+
# # generate accessor method for traversing and adding relationship on incoming nodes.
|
56
|
+
# class FileNode
|
57
|
+
# include Neo4j::ActiveNode
|
58
|
+
# has_one(:folder).from(FolderNode.files)
|
59
|
+
# # or same as
|
60
|
+
# has_one(:folder).from(FolderNode, :files)
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
#
|
64
|
+
# @return [Neo4j::ActiveNode::HasN::DeclRel] a DSL object where the has_n relationship can be further specified
|
65
|
+
def has_n(rel_type)
|
66
|
+
clazz = self
|
67
|
+
module_eval(%Q{
|
68
|
+
def #{rel_type}()
|
69
|
+
dsl = _decl_rels_for('#{rel_type}'.to_sym)
|
70
|
+
Neo4j::ActiveNode::HasN::Nodes.new(self, dsl)
|
71
|
+
end}, __FILE__, __LINE__)
|
72
|
+
|
73
|
+
|
74
|
+
module_eval(%Q{
|
75
|
+
def #{rel_type}_rels
|
76
|
+
dsl = _decl_rels_for('#{rel_type}'.to_sym)
|
77
|
+
dsl.all_relationships(self)
|
78
|
+
end}, __FILE__, __LINE__)
|
79
|
+
|
80
|
+
instance_eval(%Q{
|
81
|
+
def #{rel_type}
|
82
|
+
_decl_rels[:#{rel_type}].rel_type
|
83
|
+
end}, __FILE__, __LINE__)
|
84
|
+
|
85
|
+
_decl_rels[rel_type.to_sym] = DeclRel.new(rel_type, false, clazz)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# Specifies a relationship between two node classes.
|
90
|
+
# Generates assignment and accessor methods for the given relationship
|
91
|
+
# Old relationship is deleted when a new relationship is assigned.
|
92
|
+
# Both incoming and outgoing relationships can be declared, see {Neo4j::Wrapper::HasN::DeclRel}
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
#
|
96
|
+
# class FileNode
|
97
|
+
# include Neo4j::ActiveNode
|
98
|
+
# has_one(:folder)
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# file = FileNode.create
|
102
|
+
# file.folder = Neo4j::Node.create
|
103
|
+
# file.folder # => the node above
|
104
|
+
# file.folder_rel # => the relationship object between those nodes
|
105
|
+
#
|
106
|
+
# @return [Neo4j::ActiveNode::HasN::DeclRel] a DSL object where the has_one relationship can be futher specified
|
107
|
+
def has_one(rel_type)
|
108
|
+
clazz = self
|
109
|
+
module_eval(%Q{def #{rel_type}=(value)
|
110
|
+
dsl = _decl_rels_for(:#{rel_type})
|
111
|
+
rel = dsl.single_relationship(self)
|
112
|
+
rel && rel.del
|
113
|
+
dsl.create_relationship_to(self, value) if value
|
114
|
+
end}, __FILE__, __LINE__)
|
115
|
+
|
116
|
+
module_eval(%Q{def #{rel_type}
|
117
|
+
dsl = _decl_rels_for('#{rel_type}'.to_sym)
|
118
|
+
dsl.single_node(self)
|
119
|
+
end}, __FILE__, __LINE__)
|
120
|
+
|
121
|
+
module_eval(%Q{def #{rel_type}_rel
|
122
|
+
dsl = _decl_rels_for(:#{rel_type})
|
123
|
+
dsl.single_relationship(self)
|
124
|
+
end}, __FILE__, __LINE__)
|
125
|
+
|
126
|
+
instance_eval(%Q{
|
127
|
+
def #{rel_type}
|
128
|
+
_decl_rels[:#{rel_type}].rel_type
|
129
|
+
end}, __FILE__, __LINE__)
|
130
|
+
|
131
|
+
_decl_rels[rel_type.to_sym] = DeclRel.new(rel_type, true, clazz)
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module ActiveNode
|
3
|
+
module HasN
|
4
|
+
|
5
|
+
|
6
|
+
# A DSL for declared relationships has_n and has_one
|
7
|
+
# This DSL will be used to create accessor methods for relationships.
|
8
|
+
# Instead of using the 'raw' Neo4j::ActiveNode#rels method where one needs to know
|
9
|
+
# the name of relationship and direction one can use the generated accessor methods.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# class Folder
|
14
|
+
# include Neo4j::ActiveNode
|
15
|
+
# property :name
|
16
|
+
# # Declaring a Many relationship to any other node
|
17
|
+
# has_n(:files)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# class File
|
21
|
+
# include Neo4j::ActiveNode
|
22
|
+
# # declaring a incoming relationship from Folder's relationship files
|
23
|
+
# has_one(:folder).from(Folder, :files)
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# The following methods will be generated:
|
27
|
+
# <b>Folder#files</b> :: returns an Enumerable of outgoing nodes for relationship 'files'
|
28
|
+
# <b>Folder#files_rels</b> :: returns an Enumerable of outgoing relationships for relationship 'files'
|
29
|
+
# <b>File#folder</b> :: for adding one node for the relationship 'files' from the outgoing Folder node
|
30
|
+
# <b>File#folder_rel</b> :: for accessing relationship 'files' from the outgoing Folder node
|
31
|
+
# <b>File#folder</b> :: for accessing nodes from relationship 'files' from the outgoing Folder node
|
32
|
+
#
|
33
|
+
class DeclRel
|
34
|
+
attr_reader :source_class, :dir, :rel_type, :method_id
|
35
|
+
|
36
|
+
def initialize(method_id, has_one, source_class)
|
37
|
+
@method_id = method_id
|
38
|
+
@has_one = has_one
|
39
|
+
@dir = :outgoing
|
40
|
+
@rel_type = method_id.to_sym
|
41
|
+
@source_class = source_class
|
42
|
+
end
|
43
|
+
|
44
|
+
def inherit_new
|
45
|
+
base = self
|
46
|
+
dr = DeclRel.new(@method_id, @has_one, @source_class)
|
47
|
+
dr.instance_eval do
|
48
|
+
@dir = base.dir
|
49
|
+
@rel_type = base.rel_type
|
50
|
+
@target_name = base.target_name if base.target_name
|
51
|
+
@source_class = base.source_class
|
52
|
+
end
|
53
|
+
dr
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
"DeclRel #{object_id} dir: #{@dir} rel_id: #{@method_id}, rel_type: #{@rel_type}, target_class:#{@target_name}"
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [true, false]
|
61
|
+
def has_one?
|
62
|
+
@has_one
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [true, false]
|
66
|
+
def has_n?
|
67
|
+
!@has_one
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [true,false]
|
71
|
+
def incoming? #:nodoc:
|
72
|
+
@dir == :incoming
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Declares an outgoing relationship type.
|
77
|
+
# It is possible to prefix relationship types so that it's possible to distinguish different incoming relationships.
|
78
|
+
# There is no validation that the added node is of the specified class.
|
79
|
+
#
|
80
|
+
# @example Example
|
81
|
+
# class FolderNode
|
82
|
+
# include Neo4j::ActiveNode
|
83
|
+
# has_n(:files).to(FileNode)
|
84
|
+
# has_one(:root).to("FileSystem") # also possible, if the class is not defined yet
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# folder = FolderNode.new
|
88
|
+
# # generate a relationship between folder and file of type 'FileNode#files'
|
89
|
+
# folder.files << FileNode.new
|
90
|
+
#
|
91
|
+
# @example relationship with a hash, user defined relationship
|
92
|
+
#
|
93
|
+
# class FolderNode
|
94
|
+
# include Neo4j::ActiveNode
|
95
|
+
# has_n(:files).to('FolderNode#files')
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# @example without prefix
|
99
|
+
#
|
100
|
+
# class FolderNode
|
101
|
+
# include Neo4j::ActiveNode
|
102
|
+
# has_n(:files).to(:contains)
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# file = FileNode.new
|
106
|
+
# # create an outgoing relationship of type 'contains' from folder node to file
|
107
|
+
# folder.files << FolderNode.new
|
108
|
+
#
|
109
|
+
# @param [Class, String, Symbol] target the other class to which this relationship goes (if String or Class) or the relationship (if Symbol)
|
110
|
+
# @param [String, Symbol] rel_type the rel_type postfix for the relationships, which defaults to the same as the has_n/one method id
|
111
|
+
# @return self
|
112
|
+
def to(target, rel_type = @method_id)
|
113
|
+
@dir = :outgoing
|
114
|
+
|
115
|
+
case target
|
116
|
+
when /#/
|
117
|
+
@target_name, _ = target.to_s.split("#")
|
118
|
+
@rel_type = target.to_sym
|
119
|
+
when Class, String
|
120
|
+
@target_name = target.to_s
|
121
|
+
@rel_type = "#{@source_class}##{rel_type}".to_sym
|
122
|
+
when Symbol
|
123
|
+
@target_name = nil
|
124
|
+
@rel_type = target.to_sym
|
125
|
+
else
|
126
|
+
raise "Expected a class or a symbol for, got #{target}/#{target.class}"
|
127
|
+
end
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
# Specifies an incoming relationship.
|
132
|
+
# Will use the outgoing relationship given by the from class.
|
133
|
+
#
|
134
|
+
# @example with prefix FileNode
|
135
|
+
# class FolderNode
|
136
|
+
# include Neo4j::NodeMixin
|
137
|
+
# has_n(:files).to(FileNode)
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# class FileNode
|
141
|
+
# include Neo4j::NodeMixin
|
142
|
+
# # will only traverse any incoming relationship of type files from node FileNode
|
143
|
+
# has_one(:folder).from(FolderNode.files)
|
144
|
+
# # alternative: has_one(:folder).from(FolderNode, :files)
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
# file = FileNode.new
|
148
|
+
# # create an outgoing relationship of type 'FileNode#files' from folder node to file (FileNode is the prefix).
|
149
|
+
# file.folder = FolderNode.new
|
150
|
+
#
|
151
|
+
# @example without prefix
|
152
|
+
#
|
153
|
+
# class FolderNode
|
154
|
+
# include Neo4j::NodeMixin
|
155
|
+
# has_n(:files)
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# class FileNode
|
159
|
+
# include Neo4j::NodeMixin
|
160
|
+
# has_one(:folder).from(:files) # will traverse any incoming relationship of type files
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# file = FileNode.new
|
164
|
+
# # create an outgoing relationship of type 'files' from folder node to file
|
165
|
+
# file.folder = FolderNode.new
|
166
|
+
#
|
167
|
+
#
|
168
|
+
def from(target, rel_type=@method_id)
|
169
|
+
@dir = :incoming
|
170
|
+
|
171
|
+
case target
|
172
|
+
when /#/
|
173
|
+
@target_name, _ = target.to_s.split("#")
|
174
|
+
@rel_type = target
|
175
|
+
when Class, String
|
176
|
+
@target_name = target.to_s
|
177
|
+
@rel_type = "#{@target_name}##{rel_type}".to_sym
|
178
|
+
when Symbol
|
179
|
+
@target_name = nil
|
180
|
+
@rel_type = target.to_sym
|
181
|
+
else
|
182
|
+
raise "Expected a class or a symbol for, got #{target}/#{target.class}"
|
183
|
+
end
|
184
|
+
self
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
# @private
|
189
|
+
def target_name
|
190
|
+
@target_name
|
191
|
+
end
|
192
|
+
|
193
|
+
def target_class
|
194
|
+
@target_name && @target_name.split("::").inject(Kernel) { |container, name| container.const_get(name.to_s) }
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
# @private
|
199
|
+
def each_node(node, &block)
|
200
|
+
node.nodes(dir: dir, type: rel_type).each { |n| block.call(n)}
|
201
|
+
end
|
202
|
+
|
203
|
+
def all_relationships(node)
|
204
|
+
# TODO fix ruby warning - warning: Enumerator.new without a block is deprecated; use Object#to_enum
|
205
|
+
Enumerator.new(self, :each_rel, node)
|
206
|
+
end
|
207
|
+
|
208
|
+
def each_rel(node, &block) #:nodoc:
|
209
|
+
node.rels(dir: dir, type: rel_type).each { |rel| block.call(rel) }
|
210
|
+
end
|
211
|
+
|
212
|
+
def single_relationship(node)
|
213
|
+
node.rel(dir: dir, type: rel_type)
|
214
|
+
end
|
215
|
+
|
216
|
+
def single_node(node)
|
217
|
+
node.node(dir: dir, type: rel_type)
|
218
|
+
end
|
219
|
+
|
220
|
+
# @private
|
221
|
+
def _each_node(node, &block) #:nodoc:
|
222
|
+
node._rels(dir: dir, type: rel_type).each do |rel|
|
223
|
+
block.call rel._other_node(node)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# @private
|
228
|
+
def create_relationship_to(node, other) # :nodoc:
|
229
|
+
from, to = incoming? ? [other, node] : [node, other]
|
230
|
+
from.create_rel(@rel_type, to)
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|