neo4j-wrapper 0.0.1-java
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -0
- data/README.rdoc +64 -0
- data/lib/db/active_tx_log +1 -0
- data/lib/db/index/lucene/node/Person_exact/_0.fdt +0 -0
- data/lib/db/index/lucene/node/Person_exact/_0.fdx +0 -0
- data/lib/db/index/lucene/node/Person_exact/_0.fnm +1 -0
- data/lib/db/index/lucene/node/Person_exact/_0.frq +0 -0
- data/lib/db/index/lucene/node/Person_exact/_0.nrm +1 -0
- data/lib/db/index/lucene/node/Person_exact/_0.prx +0 -0
- data/lib/db/index/lucene/node/Person_exact/_0.tii +0 -0
- data/lib/db/index/lucene/node/Person_exact/_0.tis +0 -0
- data/lib/db/index/lucene/node/Person_exact/_1.fdt +0 -0
- data/lib/db/index/lucene/node/Person_exact/_1.fdx +0 -0
- data/lib/db/index/lucene/node/Person_exact/_1.fnm +1 -0
- data/lib/db/index/lucene/node/Person_exact/_1.frq +0 -0
- data/lib/db/index/lucene/node/Person_exact/_1.nrm +1 -0
- data/lib/db/index/lucene/node/Person_exact/_1.prx +0 -0
- data/lib/db/index/lucene/node/Person_exact/_1.tii +0 -0
- data/lib/db/index/lucene/node/Person_exact/_1.tis +0 -0
- data/lib/db/index/lucene/node/Person_exact/_2.fdt +0 -0
- data/lib/db/index/lucene/node/Person_exact/_2.fdx +0 -0
- data/lib/db/index/lucene/node/Person_exact/_2.fnm +1 -0
- data/lib/db/index/lucene/node/Person_exact/_2.frq +0 -0
- data/lib/db/index/lucene/node/Person_exact/_2.nrm +1 -0
- data/lib/db/index/lucene/node/Person_exact/_2.prx +0 -0
- data/lib/db/index/lucene/node/Person_exact/_2.tii +0 -0
- data/lib/db/index/lucene/node/Person_exact/_2.tis +0 -0
- data/lib/db/index/lucene/node/Person_exact/segments.gen +0 -0
- data/lib/db/index/lucene/node/Person_exact/segments_3 +0 -0
- data/lib/db/index/lucene-store.db +0 -0
- data/lib/db/index/lucene.log.active +0 -0
- data/lib/db/index.db +0 -0
- data/lib/db/messages.log +826 -0
- data/lib/db/neostore +0 -0
- data/lib/db/neostore.id +0 -0
- data/lib/db/neostore.nodestore.db +0 -0
- data/lib/db/neostore.nodestore.db.id +0 -0
- data/lib/db/neostore.propertystore.db +0 -0
- data/lib/db/neostore.propertystore.db.arrays +0 -0
- data/lib/db/neostore.propertystore.db.arrays.id +0 -0
- data/lib/db/neostore.propertystore.db.id +0 -0
- data/lib/db/neostore.propertystore.db.index +0 -0
- data/lib/db/neostore.propertystore.db.index.id +0 -0
- data/lib/db/neostore.propertystore.db.index.keys +0 -0
- data/lib/db/neostore.propertystore.db.index.keys.id +0 -0
- data/lib/db/neostore.propertystore.db.strings +0 -0
- data/lib/db/neostore.propertystore.db.strings.id +0 -0
- data/lib/db/neostore.relationshipstore.db +0 -0
- data/lib/db/neostore.relationshipstore.db.id +0 -0
- data/lib/db/neostore.relationshiptypestore.db +0 -0
- data/lib/db/neostore.relationshiptypestore.db.id +0 -0
- data/lib/db/neostore.relationshiptypestore.db.names +0 -0
- data/lib/db/neostore.relationshiptypestore.db.names.id +0 -0
- data/lib/db/nioneo_logical.log.active +0 -0
- data/lib/db/tm_tx_log.1 +0 -0
- data/lib/example.rb +34 -0
- data/lib/neo4j/identity_map.rb +109 -0
- data/lib/neo4j/node_mixin.rb +74 -0
- data/lib/neo4j/relationship_mixin.rb +62 -0
- data/lib/neo4j/type_converters/type_converters.rb +333 -0
- data/lib/neo4j-wrapper/class_methods.rb +27 -0
- data/lib/neo4j-wrapper/find.rb +65 -0
- data/lib/neo4j-wrapper/has_n/class_methods.rb +131 -0
- data/lib/neo4j-wrapper/has_n/decl_rel.rb +261 -0
- data/lib/neo4j-wrapper/has_n/instance_methods.rb +12 -0
- data/lib/neo4j-wrapper/has_n/nodes.rb +83 -0
- data/lib/neo4j-wrapper/node_mixin/class_methods.rb +53 -0
- data/lib/neo4j-wrapper/node_mixin/delegates.rb +140 -0
- data/lib/neo4j-wrapper/node_mixin/initialize.rb +43 -0
- data/lib/neo4j-wrapper/properties/class_methods.rb +150 -0
- data/lib/neo4j-wrapper/relationship_mixin/class_methods.rb +30 -0
- data/lib/neo4j-wrapper/relationship_mixin/delegates.rb +110 -0
- data/lib/neo4j-wrapper/relationship_mixin/initialize.rb +35 -0
- data/lib/neo4j-wrapper/rule/class_methods.rb +204 -0
- data/lib/neo4j-wrapper/rule/event_listener.rb +66 -0
- data/lib/neo4j-wrapper/rule/functions/count.rb +45 -0
- data/lib/neo4j-wrapper/rule/functions/function.rb +76 -0
- data/lib/neo4j-wrapper/rule/functions/sum.rb +31 -0
- data/lib/neo4j-wrapper/rule/instance_methods.rb +16 -0
- data/lib/neo4j-wrapper/rule/neo4j_core_ext/traverser.rb +29 -0
- data/lib/neo4j-wrapper/rule/rule.rb +134 -0
- data/lib/neo4j-wrapper/rule/rule_node.rb +205 -0
- data/lib/neo4j-wrapper/version.rb +5 -0
- data/lib/neo4j-wrapper/wrapper.rb +38 -0
- data/lib/neo4j-wrapper.rb +35 -0
- data/lib/test.rb +61 -0
- data/neo4j-wrapper.gemspec +31 -0
- metadata +162 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Wrapper
|
3
|
+
module Find
|
4
|
+
Neo4j::Core::Index::ClassMethods.send(:alias_method, :_orig_find, :find)
|
5
|
+
|
6
|
+
# If the #ref_node_for_class returns an object implementing the method #_index_prefix it
|
7
|
+
# will use that as prefix, otherwise the empty string.
|
8
|
+
# @return [String] the prefix name of the index
|
9
|
+
def index_prefix
|
10
|
+
return "" unless Neo4j.running?
|
11
|
+
return "" unless respond_to?(:ref_node_for_class)
|
12
|
+
ref_node = ref_node_for_class.wrapper
|
13
|
+
prefix = ref_node.send(:index_prefix) if ref_node.respond_to?(:index_prefix)
|
14
|
+
prefix ? prefix + "_" : ""
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# @return [String] the name of the index, with index prefix
|
19
|
+
def _index_name
|
20
|
+
to_s.gsub("::", '_')
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fall back to the threadlocal ref node by default.
|
24
|
+
# You can set your own reference node using the #ref_node method
|
25
|
+
# @return [Neo4j::Node] returns the Neo4j.ref_node
|
26
|
+
def ref_node_for_class
|
27
|
+
Neo4j.ref_node
|
28
|
+
end
|
29
|
+
|
30
|
+
# Assigns the reference node for a class via a supplied block.
|
31
|
+
#
|
32
|
+
# @example of usage:
|
33
|
+
# class Person
|
34
|
+
# include Neo4j::NodeMixin
|
35
|
+
# ref_node { Neo4j.default_ref_node }
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
def ref_node(&block)
|
39
|
+
singleton = class << self;
|
40
|
+
self;
|
41
|
+
end
|
42
|
+
singleton.send(:define_method, :ref_node_for_class) { block.call }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Overrides the Neo4j::Core::Index::ClassMethods#find method to check
|
46
|
+
# if any of the query parameters needs to be converted, (e.g. DateTime to Fixnum)
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# Person.find(:since => (1.year.ago .. Time.now))
|
50
|
+
# @see http://rdoc.info/github/andreasronge/neo4j-core/Neo4j/Core/Index/Indexer#find-instance_method Neo4j::Core::Index::ClassMethods#find
|
51
|
+
def find(*query_params)
|
52
|
+
query = query_params.first
|
53
|
+
if query.is_a?(Hash)
|
54
|
+
query.each_pair do |k, v|
|
55
|
+
converter = _converter(k)
|
56
|
+
value = v.is_a?(Range) ? Range.new(converter.to_java(v.begin), converter.to_java(v.end), v.exclude_end?) : converter.to_java(v)
|
57
|
+
query[k] = value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
_orig_find(*query_params)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Wrapper
|
3
|
+
module HasN
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
# @return [Hash] a hash of all relationship and its configuration defined by has_n and has_one
|
7
|
+
def _decl_rels
|
8
|
+
@_decl_rels ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
# make sure the inherited classes inherit the <tt>_decl_rels</tt> hash
|
12
|
+
def inherited(klass)
|
13
|
+
copy = _decl_rels.clone
|
14
|
+
copy.each_pair{|k,v| copy[k] = v.inherit_new}
|
15
|
+
klass.instance_variable_set(:@_decl_rels, copy)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# Specifies a relationship between two node classes.
|
21
|
+
# Generates assignment and accessor methods for the given relationship.
|
22
|
+
# Both incoming and outgoing relationships can be declared, see {Neo4j::Wrapper::HasN::DeclRel}
|
23
|
+
#
|
24
|
+
# @example has_n(:files)
|
25
|
+
#
|
26
|
+
# class FolderNode
|
27
|
+
# include Ne4j::NodeMixin
|
28
|
+
# has_n(:files)
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# folder = FolderNode.new
|
32
|
+
# folder.files << Neo4j::Node.new << Neo4j::Node.new
|
33
|
+
# folder.files.inject {...}
|
34
|
+
#
|
35
|
+
# FolderNode.files #=> 'files' the name of the relationship
|
36
|
+
#
|
37
|
+
# @example has_n(x).to(...)
|
38
|
+
#
|
39
|
+
# # You can declare which class it has relationship to.
|
40
|
+
# # The generated relationships will be prefixed with the name of that class.
|
41
|
+
# class FolderNode
|
42
|
+
# include Ne4j::NodeMixin
|
43
|
+
# has_n(:files).to(File)
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# FolderNode.files #=> 'File#files' the name of the relationship
|
47
|
+
#
|
48
|
+
# @example has_n(x).from(class, has_n_name)
|
49
|
+
#
|
50
|
+
# # generate accessor method for traversing and adding relationship on incoming nodes.
|
51
|
+
# class FileNode
|
52
|
+
# include Ne4j::NodeMixin
|
53
|
+
# has_one(:folder).from(FolderNode, :files)
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
#
|
57
|
+
# @return [Neo4j::Wrapper::HasN::DeclRel] a DSL object where the has_n relationship can be futher specified
|
58
|
+
def has_n(rel_type)
|
59
|
+
clazz = self
|
60
|
+
module_eval(%Q{
|
61
|
+
def #{rel_type}
|
62
|
+
dsl = _decl_rels_for('#{rel_type}'.to_sym)
|
63
|
+
Neo4j::Wrapper::HasN::Nodes.new(self, dsl)
|
64
|
+
end}, __FILE__, __LINE__)
|
65
|
+
|
66
|
+
|
67
|
+
module_eval(%Q{
|
68
|
+
def #{rel_type}_rels
|
69
|
+
dsl = _decl_rels_for('#{rel_type}'.to_sym)
|
70
|
+
dsl.all_relationships(self)
|
71
|
+
end}, __FILE__, __LINE__)
|
72
|
+
|
73
|
+
instance_eval(%Q{
|
74
|
+
def #{rel_type}
|
75
|
+
_decl_rels[:#{rel_type}].rel_type.to_s
|
76
|
+
end}, __FILE__, __LINE__)
|
77
|
+
|
78
|
+
_decl_rels[rel_type.to_sym] = DeclRel.new(rel_type, false, clazz)
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Specifies a relationship between two node classes.
|
83
|
+
# Generates assignment and accessor methods for the given relationship
|
84
|
+
# Old relationship is deleted when a new relationship is assigned.
|
85
|
+
# Both incoming and outgoing relationships can be declared, see {Neo4j::Wrapper::HasN::DeclRel}
|
86
|
+
#
|
87
|
+
# @example
|
88
|
+
#
|
89
|
+
# class FileNode
|
90
|
+
# include Ne4j::NodeMixin
|
91
|
+
# has_one(:folder)
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# file = FileNode.new
|
95
|
+
# file.folder = Neo4j::Node.new
|
96
|
+
# file.folder # => the node above
|
97
|
+
# file.folder_rel # => the relationship object between those nodes
|
98
|
+
#
|
99
|
+
# @return [Neo4j::Wrapper::HasN::DeclRel] a DSL object where the has_one relationship can be futher specified
|
100
|
+
def has_one(rel_type)
|
101
|
+
clazz = self
|
102
|
+
module_eval(%Q{def #{rel_type}=(value)
|
103
|
+
dsl = _decl_rels_for(:#{rel_type})
|
104
|
+
rel = dsl.single_relationship(self)
|
105
|
+
rel.del unless rel.nil?
|
106
|
+
dsl.create_relationship_to(self, value) if value
|
107
|
+
end}, __FILE__, __LINE__)
|
108
|
+
|
109
|
+
module_eval(%Q{def #{rel_type}
|
110
|
+
dsl = _decl_rels_for(:#{rel_type})
|
111
|
+
dsl.single_node(self)
|
112
|
+
end}, __FILE__, __LINE__)
|
113
|
+
|
114
|
+
module_eval(%Q{def #{rel_type}_rel
|
115
|
+
dsl = _decl_rels_for(:#{rel_type})
|
116
|
+
dsl.single_relationship(self)
|
117
|
+
end}, __FILE__, __LINE__)
|
118
|
+
|
119
|
+
instance_eval(%Q{
|
120
|
+
def #{rel_type}
|
121
|
+
_decl_rels[:#{rel_type}].rel_type.to_s
|
122
|
+
end}, __FILE__, __LINE__)
|
123
|
+
|
124
|
+
_decl_rels[rel_type.to_sym] = DeclRel.new(rel_type, true, clazz)
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,261 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Wrapper
|
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::NodeMixin#rels method where one needs to know
|
9
|
+
# the name of relationship and direction one can use the generated accessor methods.
|
10
|
+
#
|
11
|
+
# The DSL can also be used to specify a mapping to a Ruby class for a relationship, see Neo4j::HasN::DeclRelationshipDsl#relationship
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# class Folder
|
16
|
+
# include Neo4j::NodeMixin
|
17
|
+
# property :name
|
18
|
+
# # Declaring a Many relationship to any other node
|
19
|
+
# has_n(:files)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# class File
|
23
|
+
# include Neo4j::NodeMixin
|
24
|
+
# # declaring a incoming relationship from Folder's relationship files
|
25
|
+
# has_one(:folder).from(Folder, :files)
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# The following methods will be generated:
|
29
|
+
# <b>Folder#files</b> :: returns an Enumerable of outgoing nodes for relationship 'files'
|
30
|
+
# <b>Folder#files_rels</b> :: returns an Enumerable of outgoing relationships for relationship 'files'
|
31
|
+
# <b>File#folder</b> :: for adding one node for the relationship 'files' from the outgoing Folder node
|
32
|
+
# <b>File#folder_rel</b> :: for accessing relationship 'files' from the outgoing Folder node
|
33
|
+
# <b>File#folder</b> :: for accessing nodes from relationship 'files' from the outgoing Folder node
|
34
|
+
#
|
35
|
+
class DeclRel
|
36
|
+
attr_reader :target_class, :source_class, :dir, :rel_type
|
37
|
+
|
38
|
+
def initialize(method_id, has_one, target_class)
|
39
|
+
@method_id = method_id
|
40
|
+
@has_one = has_one
|
41
|
+
@target_class = target_class
|
42
|
+
@dir = :outgoing
|
43
|
+
@rel_type = method_id.to_s
|
44
|
+
@source_class = target_class
|
45
|
+
end
|
46
|
+
|
47
|
+
def inherit_new
|
48
|
+
base = self
|
49
|
+
dr = DeclRel.new(@method_id, @has_one, @target_class)
|
50
|
+
dr.instance_eval do
|
51
|
+
@dir = base.dir
|
52
|
+
@rel_type = base.rel_type
|
53
|
+
@source_class = base.source_class
|
54
|
+
end
|
55
|
+
dr
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_s
|
59
|
+
"DeclRel #{object_id} dir: #{@dir} rel_id: #{@method_id}, rel_type: #{@rel_type}, target_class:#{@target_class} rel_class:#{@relationship}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [true, false]
|
63
|
+
def has_one?
|
64
|
+
@has_one
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [true, false]
|
68
|
+
def has_n?
|
69
|
+
!@has_one
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [true,false]
|
73
|
+
def incoming? #:nodoc:
|
74
|
+
@dir == :incoming
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# Specifies an outgoing relationship.
|
79
|
+
# The name of the outgoing class will be used as a prefix for the relationship used.
|
80
|
+
#
|
81
|
+
# @example Example
|
82
|
+
# class FolderNode
|
83
|
+
# include Neo4j::NodeMixin
|
84
|
+
# has_n(:files).to(FileNode)
|
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 without prefix
|
92
|
+
#
|
93
|
+
# class FolderNode
|
94
|
+
# include Neo4j::NodeMixin
|
95
|
+
# has_n(:files).to(:contains)
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# file = FileNode.new
|
99
|
+
# # create an outgoing relationship of type 'contains' from folder node to file
|
100
|
+
# folder.files << FolderNode.new
|
101
|
+
#
|
102
|
+
# @param [Class] target the other class to which this relationship goes
|
103
|
+
# @return self
|
104
|
+
def to(target)
|
105
|
+
@dir = :outgoing
|
106
|
+
|
107
|
+
if Class === target
|
108
|
+
# handle e.g. has_n(:friends).to(class)
|
109
|
+
@target_class = target
|
110
|
+
@rel_type = "#{@source_class}##{@method_id}"
|
111
|
+
elsif Symbol === target
|
112
|
+
# handle e.g. has_n(:friends).to(:knows)
|
113
|
+
@rel_type = target.to_s
|
114
|
+
else
|
115
|
+
raise "Expected a class or a symbol for, got #{target}/#{target.class}"
|
116
|
+
end
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
# Specifies an incoming relationship.
|
121
|
+
# Will use the outgoing relationship given by the from class.
|
122
|
+
#
|
123
|
+
# @example with prefix FileNode
|
124
|
+
# class FolderNode
|
125
|
+
# include Neo4j::NodeMixin
|
126
|
+
# has_n(:files).to(FileNode)
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# class FileNode
|
130
|
+
# include Neo4j::NodeMixin
|
131
|
+
# # will only traverse any incoming relationship of type files from node FileNode
|
132
|
+
# has_one(:folder).from(FolderNode, :files)
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# file = FileNode.new
|
136
|
+
# # create an outgoing relationship of type 'FileNode#files' from folder node to file (FileNode is the prefix).
|
137
|
+
# file.folder = FolderNode.new
|
138
|
+
#
|
139
|
+
# @example without prefix
|
140
|
+
#
|
141
|
+
# class FolderNode
|
142
|
+
# include Neo4j::NodeMixin
|
143
|
+
# has_n(:files)
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# class FileNode
|
147
|
+
# include Neo4j::NodeMixin
|
148
|
+
# has_one(:folder).from(:files) # will traverse any incoming relationship of type files
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# file = FileNode.new
|
152
|
+
# # create an outgoing relationship of type 'files' from folder node to file
|
153
|
+
# file.folder = FolderNode.new
|
154
|
+
#
|
155
|
+
#
|
156
|
+
def from(*args)
|
157
|
+
@dir = :incoming
|
158
|
+
|
159
|
+
if args.size > 1
|
160
|
+
# handle specified (prefixed) relationship, e.g. has_n(:known_by).from(clazz, :type)
|
161
|
+
@target_class = args[0]
|
162
|
+
@rel_type = "#{@target_class}##{args[1]}"
|
163
|
+
@relationship_name = args[1].to_sym
|
164
|
+
elsif Symbol === args[0]
|
165
|
+
# handle unspecified (unprefixed) relationship, e.g. has_n(:known_by).from(:type)
|
166
|
+
@rel_type = args[0].to_s
|
167
|
+
else
|
168
|
+
raise "Expected a symbol for, got #{args[0]}"
|
169
|
+
end
|
170
|
+
self
|
171
|
+
end
|
172
|
+
|
173
|
+
# Specifies which relationship ruby class to use for the relationship
|
174
|
+
#
|
175
|
+
# @example
|
176
|
+
#
|
177
|
+
# class OrderLine
|
178
|
+
# include Neo4j::RelationshipMixin
|
179
|
+
# property :units
|
180
|
+
# property :unit_price
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# class Order
|
184
|
+
# property :total_cost
|
185
|
+
# property :dispatched
|
186
|
+
# has_n(:products).to(Product).relationship(OrderLine)
|
187
|
+
# end
|
188
|
+
#
|
189
|
+
# order = Order.new
|
190
|
+
# order.products << Product.new
|
191
|
+
# order.products_rels.first # => OrderLine
|
192
|
+
#
|
193
|
+
def relationship(rel_class)
|
194
|
+
@relationship = rel_class
|
195
|
+
self
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# @private
|
200
|
+
def relationship_class # :nodoc:
|
201
|
+
if !@relationship_name.nil? && @relationship.nil?
|
202
|
+
other_class_dsl = @target_class._decl_rels[@relationship_name]
|
203
|
+
if other_class_dsl
|
204
|
+
@relationship = other_class_dsl.relationship_class
|
205
|
+
else
|
206
|
+
Neo4j.logger.warn "Unknown outgoing relationship #{@relationship_name} on #{@target_class}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
@relationship
|
210
|
+
end
|
211
|
+
|
212
|
+
# @private
|
213
|
+
def each_node(node, &block)
|
214
|
+
node.rels(dir, rel_type).each do |rel|
|
215
|
+
block.call(rel.other_node(node))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# @private
|
220
|
+
def _each_node(node, &block) #:nodoc:
|
221
|
+
node._rels(dir, rel_type).each do |rel|
|
222
|
+
block.call rel._other_node(node)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# @private
|
227
|
+
def single_node(node)
|
228
|
+
rel = single_relationship(node)
|
229
|
+
rel && rel.other_node(node)
|
230
|
+
end
|
231
|
+
|
232
|
+
# @private
|
233
|
+
def single_relationship(node) #:nodoc:
|
234
|
+
node.rel(dir, rel_type)
|
235
|
+
end
|
236
|
+
|
237
|
+
# @private
|
238
|
+
def _all_relationships(node) #:nodoc:
|
239
|
+
node._rels(dir, rel_type)
|
240
|
+
end
|
241
|
+
|
242
|
+
# @private
|
243
|
+
def all_relationships(node)
|
244
|
+
node.rels(dir, rel_type)
|
245
|
+
end
|
246
|
+
|
247
|
+
# @private
|
248
|
+
def create_relationship_to(node, other) # :nodoc:
|
249
|
+
from, to = incoming? ? [other, node] : [node, other]
|
250
|
+
|
251
|
+
if relationship_class
|
252
|
+
relationship_class.new(@rel_type, from._java_node, to._java_node)
|
253
|
+
else
|
254
|
+
Neo4j::Relationship.new(@rel_type, from, to)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Wrapper
|
3
|
+
module HasN
|
4
|
+
# The {Neo4j::Wrapper::HasN::ClassMethods} generates has_n relationship accessor methods.
|
5
|
+
module InstanceMethods
|
6
|
+
def _decl_rels_for(rel_type)
|
7
|
+
self.class._decl_rels[rel_type]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Wrapper
|
3
|
+
module HasN
|
4
|
+
|
5
|
+
# The object created by a has_n or has_one Neo4j::NodeMixin class method which enables creating and traversal of nodes.
|
6
|
+
#
|
7
|
+
# @see Neo4j::Wrapper::HasN::ClassMethods
|
8
|
+
class Nodes
|
9
|
+
include Enumerable
|
10
|
+
include Neo4j::Core::ToJava
|
11
|
+
|
12
|
+
def initialize(node, decl_rel) # :nodoc:
|
13
|
+
@node = node
|
14
|
+
@decl_rel = decl_rel
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"HasN::Nodes [#{@decl_rel.dir}, id: #{@node.neo_id} type: #{@decl_rel && @decl_rel.rel_type} decl_rel:#{@decl_rel}]"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Traverse the relationship till the index position
|
22
|
+
# @return [Neo4j::NodeMixin,Neo4j::Node,nil] the node at the given position
|
23
|
+
def [](index)
|
24
|
+
i = 0
|
25
|
+
each { |x| return x if i == index; i += 1 }
|
26
|
+
nil # out of index
|
27
|
+
end
|
28
|
+
|
29
|
+
# Pretend we are an array - this is necessarily for Rails actionpack/actionview/formhelper to work with this
|
30
|
+
def is_a?(type)
|
31
|
+
# ActionView requires this for nested attributes to work
|
32
|
+
return true if Array == type
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
# Required by the Enumerable mixin.
|
37
|
+
def each
|
38
|
+
@decl_rel.each_node(@node) { |n| yield n } # Should use yield here as passing &block through doesn't always work (why?)
|
39
|
+
end
|
40
|
+
|
41
|
+
# returns none wrapped nodes, you may get better performance using this method
|
42
|
+
def _each
|
43
|
+
@decl_rel._each_node(@node) { |n| yield n }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns an real ruby array.
|
47
|
+
def to_ary
|
48
|
+
self.to_a
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns true if there are no node in this type of relationship
|
52
|
+
def empty?
|
53
|
+
first == nil
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# Creates a relationship instance between this and the other node.
|
58
|
+
# Returns the relationship object
|
59
|
+
def new(other)
|
60
|
+
@decl_rel.create_relationship_to(@node, other)
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# Creates a relationship between this and the other node.
|
65
|
+
#
|
66
|
+
# @example Person includes the Neo4j::NodeMixin and declares a has_n :friends
|
67
|
+
#
|
68
|
+
# p = Person.new # Node has declared having a friend type of relationship
|
69
|
+
# n1 = Node.new
|
70
|
+
# n2 = Node.new
|
71
|
+
#
|
72
|
+
# p.friends << n2 << n3
|
73
|
+
#
|
74
|
+
# @return self
|
75
|
+
def <<(other)
|
76
|
+
@decl_rel.create_relationship_to(@node, other)
|
77
|
+
self
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Wrapper
|
3
|
+
module NodeMixin
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
# Creates a new node or loads an already existing Neo4j node.
|
7
|
+
#
|
8
|
+
# You can use two callback method to initialize the node
|
9
|
+
# init_on_load - this method is called when the node is loaded from the database
|
10
|
+
# init_on_create - called when the node is created, will be provided with the same argument as the new method
|
11
|
+
#
|
12
|
+
# == Does
|
13
|
+
# * sets the neo4j property '_classname' to self.class.to_s
|
14
|
+
# * creates a neo4j node java object (in @_java_node)
|
15
|
+
#
|
16
|
+
# If you want to provide your own initialize method you should instead implement the
|
17
|
+
# method init_on_create method.
|
18
|
+
#
|
19
|
+
# @example Create your own Ruby wrapper around a Neo4j::Node java object
|
20
|
+
# class MyNode
|
21
|
+
# include Neo4j::NodeMixin
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# node = MyNode.new(:name => 'jimmy', :age => 23)
|
25
|
+
#
|
26
|
+
# @example Using your own initialize method
|
27
|
+
# class MyNode
|
28
|
+
# include Neo4j::NodeMixin
|
29
|
+
#
|
30
|
+
# def init_on_create(name, age)
|
31
|
+
# self[:name] = name
|
32
|
+
# self[:age] = age
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# node = MyNode.new('jimmy', 23)
|
37
|
+
#
|
38
|
+
# @param args typically a hash of properties, but could be anything which will be handled in the super method
|
39
|
+
# @return the object return from the super method
|
40
|
+
def new(*args)
|
41
|
+
node = Neo4j::Node.create
|
42
|
+
wrapped_node = super()
|
43
|
+
Neo4j::IdentityMap.add(node, wrapped_node)
|
44
|
+
wrapped_node.init_on_load(node)
|
45
|
+
wrapped_node.init_on_create(*args)
|
46
|
+
wrapped_node
|
47
|
+
end
|
48
|
+
|
49
|
+
alias_method :create, :new
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|