neo4j-wrapper 0.0.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.
- 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
|