neo4j 1.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +141 -0
- data/CONTRIBUTORS +15 -0
- data/Gemfile +3 -0
- data/README.rdoc +2015 -0
- data/lib/neo4j.old/batch_inserter.rb +144 -0
- data/lib/neo4j.old/config.rb +138 -0
- data/lib/neo4j.old/event_handler.rb +73 -0
- data/lib/neo4j.old/extensions/activemodel.rb +158 -0
- data/lib/neo4j.old/extensions/aggregate.rb +12 -0
- data/lib/neo4j.old/extensions/aggregate/aggregate_enum.rb +40 -0
- data/lib/neo4j.old/extensions/aggregate/ext/node_mixin.rb +69 -0
- data/lib/neo4j.old/extensions/aggregate/node_aggregate.rb +8 -0
- data/lib/neo4j.old/extensions/aggregate/node_aggregate_mixin.rb +331 -0
- data/lib/neo4j.old/extensions/aggregate/node_aggregator.rb +216 -0
- data/lib/neo4j.old/extensions/aggregate/node_group.rb +43 -0
- data/lib/neo4j.old/extensions/aggregate/prop_group.rb +30 -0
- data/lib/neo4j.old/extensions/aggregate/property_enum.rb +24 -0
- data/lib/neo4j.old/extensions/aggregate/props_aggregate.rb +8 -0
- data/lib/neo4j.old/extensions/aggregate/props_aggregate_mixin.rb +31 -0
- data/lib/neo4j.old/extensions/aggregate/props_aggregator.rb +80 -0
- data/lib/neo4j.old/extensions/find_path.rb +117 -0
- data/lib/neo4j.old/extensions/graph_algo.rb +1 -0
- data/lib/neo4j.old/extensions/graph_algo/all_simple_paths.rb +133 -0
- data/lib/neo4j.old/extensions/graph_algo/neo4j-graph-algo-0.3.jar +0 -0
- data/lib/neo4j.old/extensions/reindexer.rb +104 -0
- data/lib/neo4j.old/extensions/rest.rb +21 -0
- data/lib/neo4j.old/extensions/rest/rest.rb +336 -0
- data/lib/neo4j.old/extensions/rest/rest_mixin.rb +193 -0
- data/lib/neo4j.old/extensions/rest/server.rb +50 -0
- data/lib/neo4j.old/extensions/rest/stubs.rb +141 -0
- data/lib/neo4j.old/extensions/rest_master.rb +34 -0
- data/lib/neo4j.old/extensions/rest_slave.rb +31 -0
- data/lib/neo4j.old/extensions/tx_tracker.rb +392 -0
- data/lib/neo4j.old/indexer.rb +187 -0
- data/lib/neo4j.old/jars.rb +6 -0
- data/lib/neo4j.old/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j.old/jars/neo4j-kernel-1.0.jar +0 -0
- data/lib/neo4j.old/mixins/java_list_mixin.rb +139 -0
- data/lib/neo4j.old/mixins/java_node_mixin.rb +205 -0
- data/lib/neo4j.old/mixins/java_property_mixin.rb +169 -0
- data/lib/neo4j.old/mixins/java_relationship_mixin.rb +60 -0
- data/lib/neo4j.old/mixins/migration_mixin.rb +157 -0
- data/lib/neo4j.old/mixins/node_mixin.rb +249 -0
- data/lib/neo4j.old/mixins/property_class_methods.rb +265 -0
- data/lib/neo4j.old/mixins/rel_class_methods.rb +167 -0
- data/lib/neo4j.old/mixins/relationship_mixin.rb +103 -0
- data/lib/neo4j.old/neo.rb +247 -0
- data/lib/neo4j.old/node.rb +49 -0
- data/lib/neo4j.old/reference_node.rb +15 -0
- data/lib/neo4j.old/relationship.rb +85 -0
- data/lib/neo4j.old/relationships/decl_relationship_dsl.rb +164 -0
- data/lib/neo4j.old/relationships/has_list.rb +101 -0
- data/lib/neo4j.old/relationships/has_n.rb +129 -0
- data/lib/neo4j.old/relationships/node_traverser.rb +138 -0
- data/lib/neo4j.old/relationships/relationship_dsl.rb +149 -0
- data/lib/neo4j.old/relationships/traversal_position.rb +50 -0
- data/lib/neo4j.old/relationships/wrappers.rb +51 -0
- data/lib/neo4j.old/search_result.rb +72 -0
- data/lib/neo4j.old/transaction.rb +254 -0
- data/lib/neo4j.old/version.rb +3 -0
- data/lib/neo4j.rb +50 -0
- data/lib/neo4j/config.rb +137 -0
- data/lib/neo4j/database.rb +43 -0
- data/lib/neo4j/equal.rb +22 -0
- data/lib/neo4j/event_handler.rb +91 -0
- data/lib/neo4j/index.rb +157 -0
- data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j/jars/lucene-core-2.9.2.jar +0 -0
- data/lib/neo4j/jars/lucene-core-3.0.1.jar +0 -0
- data/lib/neo4j/jars/neo4j-index-1.1.jar +0 -0
- data/lib/neo4j/jars/neo4j-kernel-1.1.1.jar +0 -0
- data/lib/neo4j/jars/neo4j-kernel-1.1.jar +0 -0
- data/lib/neo4j/jars/neo4j-lucene-index-0.1-20100916.085626-67.jar +0 -0
- data/lib/neo4j/mapping/class_methods/index.rb +21 -0
- data/lib/neo4j/mapping/class_methods/property.rb +139 -0
- data/lib/neo4j/mapping/class_methods/relationship.rb +96 -0
- data/lib/neo4j/mapping/class_methods/rule.rb +135 -0
- data/lib/neo4j/mapping/decl_relationship_dsl.rb +151 -0
- data/lib/neo4j/mapping/has_n.rb +117 -0
- data/lib/neo4j/mapping/node_mixin.rb +70 -0
- data/lib/neo4j/neo4j.rb +65 -0
- data/lib/neo4j/node.rb +82 -0
- data/lib/neo4j/node_mixin.rb +4 -0
- data/lib/neo4j/node_relationship.rb +60 -0
- data/lib/neo4j/node_traverser.rb +141 -0
- data/lib/neo4j/property.rb +72 -0
- data/lib/neo4j/rails/lucene_connection_closer.rb +19 -0
- data/lib/neo4j/rails/model.rb +210 -0
- data/lib/neo4j/rails/railtie.rb +16 -0
- data/lib/neo4j/rails/transaction.rb +29 -0
- data/lib/neo4j/rails/value.rb +43 -0
- data/lib/neo4j/relationship.rb +88 -0
- data/lib/neo4j/relationship_traverser.rb +57 -0
- data/lib/neo4j/to_java.rb +17 -0
- data/lib/neo4j/transaction.rb +69 -0
- data/lib/neo4j/version.rb +3 -0
- data/neo4j.gemspec +30 -0
- metadata +243 -0
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Neo4j::Mapping
|
2
|
+
module ClassMethods
|
3
|
+
module Index
|
4
|
+
def index(field, config = {})
|
5
|
+
Neo4j::Node.index(field, config, index_name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def find(field, query, config = {})
|
9
|
+
Neo4j::Node.find(field, query, config, index_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def rm_index(field, config = {})
|
13
|
+
Neo4j::Node.rm_index(field, config, index_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def index_name
|
17
|
+
root_class
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module Neo4j::Mapping
|
2
|
+
module ClassMethods
|
3
|
+
module Property
|
4
|
+
|
5
|
+
#
|
6
|
+
# Access to class constants.
|
7
|
+
# These properties are shared by the class and its siblings.
|
8
|
+
# For example that means that we can specify properties for a parent
|
9
|
+
# class and the child classes will 'inherit' those properties.
|
10
|
+
#
|
11
|
+
|
12
|
+
def root_class # :nodoc:
|
13
|
+
self::ROOT_CLASS
|
14
|
+
end
|
15
|
+
|
16
|
+
def properties_info # :nodoc:
|
17
|
+
self::PROPERTIES_INFO
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# ------------------------------------------------------------------------
|
22
|
+
|
23
|
+
|
24
|
+
# Generates accessor method and sets configuration for Neo4j node properties.
|
25
|
+
# The generated accessor is a simple wrapper around the #[] and
|
26
|
+
# #[]= operators.
|
27
|
+
#
|
28
|
+
# If a property is set to nil the property will be removed.
|
29
|
+
#
|
30
|
+
# ==== Example
|
31
|
+
# class Baaz; end
|
32
|
+
#
|
33
|
+
# class Foo
|
34
|
+
# include Neo4j::NodeMixin
|
35
|
+
# property :name, :city # can set several properties in one go
|
36
|
+
# property :bar
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# f = Foo.new
|
40
|
+
# f.bar = Baaz.new
|
41
|
+
#
|
42
|
+
def property(*props)
|
43
|
+
if props.size == 2 and props[1].kind_of?(Hash)
|
44
|
+
props[1].each_pair do |key, value|
|
45
|
+
pname = props[0].to_sym
|
46
|
+
properties_info[pname] ||= {}
|
47
|
+
properties_info[pname][key] = value
|
48
|
+
end
|
49
|
+
props = props[0..0]
|
50
|
+
end
|
51
|
+
|
52
|
+
props.each do |prop|
|
53
|
+
pname = prop.to_sym
|
54
|
+
properties_info[pname] ||= {}
|
55
|
+
properties_info[pname][:defined] = true
|
56
|
+
|
57
|
+
define_method(pname) do
|
58
|
+
self[pname]
|
59
|
+
end
|
60
|
+
|
61
|
+
name = (pname.to_s() +"=").to_sym
|
62
|
+
define_method(name) do |value|
|
63
|
+
self[pname] = value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Returns true if the given property name has been defined with the class
|
70
|
+
# method property or properties.
|
71
|
+
#
|
72
|
+
# Notice that the node may have properties that has not been declared.
|
73
|
+
# It is always possible to set an undeclared property on a node.
|
74
|
+
#
|
75
|
+
# ==== Returns
|
76
|
+
# true or false
|
77
|
+
#
|
78
|
+
def property?(prop_name)
|
79
|
+
return false if properties_info[prop_name.to_sym].nil?
|
80
|
+
properties_info[prop_name.to_sym][:defined] == true
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def load
|
85
|
+
# TODO
|
86
|
+
node = db.graph.get_node_by_id(node_id.to_i)
|
87
|
+
clazz = Neo4j::Node.to_class(node[:_classname])
|
88
|
+
raise "Expected classname #{self} got #{clazz}" if clazz != self
|
89
|
+
end
|
90
|
+
|
91
|
+
def load_wrapper(node, db = Neo4j.started_db)
|
92
|
+
wrapped_node = self.orig_new # avoid creating a new node, only a Ruby Object
|
93
|
+
wrapped_node.init_on_load(node)
|
94
|
+
wrapped_node
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
# Creates a new node or loads an already existing Neo4j node.
|
99
|
+
#
|
100
|
+
# Does
|
101
|
+
# * sets the neo4j property '_classname' to self.class.to_s
|
102
|
+
# * creates a neo4j node java object (in @_java_node)
|
103
|
+
# * calls init_node if that is defined in the current class.
|
104
|
+
#
|
105
|
+
# If you want to provide your own initialize method you should instead implement the
|
106
|
+
# method init_node method.
|
107
|
+
#
|
108
|
+
# === Example
|
109
|
+
#
|
110
|
+
# class MyNode
|
111
|
+
# include Neo4j::NodeMixin
|
112
|
+
#
|
113
|
+
# def init_node(name, age)
|
114
|
+
# self[:name] = name
|
115
|
+
# self[:age] = age
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# node = MyNode.new('jimmy', 23)
|
120
|
+
# # notice the following is still possible:
|
121
|
+
# node = MyNode :name => 'jimmy', :age => 12
|
122
|
+
#
|
123
|
+
# The init_node is only called when the node is created in the database.
|
124
|
+
# The initialize method is used both for to purposes:
|
125
|
+
# loading an already existing node from the Neo4j database and creating a new node in the database.
|
126
|
+
#
|
127
|
+
def new(*args)
|
128
|
+
node = Neo4j::Node.create
|
129
|
+
wrapped_node = super()
|
130
|
+
wrapped_node.init_on_load(node)
|
131
|
+
wrapped_node.init_on_create(*args)
|
132
|
+
wrapped_node
|
133
|
+
end
|
134
|
+
|
135
|
+
alias_method :create, :new
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Neo4j::Mapping
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
module Relationship
|
5
|
+
def decl_relationships
|
6
|
+
# :nodoc:
|
7
|
+
self::DECL_RELATIONSHIPS
|
8
|
+
end
|
9
|
+
|
10
|
+
# Specifies a relationship between two node classes.
|
11
|
+
# Generates assignment and accessor methods for the given relationship.
|
12
|
+
#
|
13
|
+
# ==== Example
|
14
|
+
#
|
15
|
+
# class FolderNode
|
16
|
+
# include Ne4j::NodeMixin
|
17
|
+
# has_n(:files)
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# folder = FolderNode.new
|
21
|
+
# folder.files << Neo4j::Node.new << Neo4j::Node.new
|
22
|
+
# folder.files.inject {...}
|
23
|
+
#
|
24
|
+
# ==== Returns
|
25
|
+
#
|
26
|
+
# Neo4j::Mapping::DeclRelationshipDsl
|
27
|
+
#
|
28
|
+
def has_n(rel_type, params = {})
|
29
|
+
clazz = self
|
30
|
+
module_eval(%Q{
|
31
|
+
def #{rel_type}(&block)
|
32
|
+
dsl = #{clazz}.decl_relationships[:'#{rel_type.to_s}']
|
33
|
+
Neo4j::Mapping::HasN.new(self, dsl, &block)
|
34
|
+
end}, __FILE__, __LINE__)
|
35
|
+
|
36
|
+
module_eval(%Q{
|
37
|
+
def #{rel_type}_rels
|
38
|
+
dsl = #{clazz}.decl_relationships[:'#{rel_type.to_s}']
|
39
|
+
Neo4j::Mapping::HasN.new(self, dsl).rels
|
40
|
+
end}, __FILE__, __LINE__)
|
41
|
+
|
42
|
+
decl_relationships[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, params)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# Specifies a relationship between two node classes.
|
47
|
+
# Generates assignment and accessor methods for the given relationship
|
48
|
+
# Old relationship is deleted when a new relationship is assigned.
|
49
|
+
#
|
50
|
+
# ==== Example
|
51
|
+
#
|
52
|
+
# class FileNode
|
53
|
+
# include Ne4j::NodeMixin
|
54
|
+
# has_one(:folder)
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# file = FileNode.new
|
58
|
+
# file.folder = Neo4j::Node.new
|
59
|
+
# file.folder # => the node above
|
60
|
+
# file.folder_rel # => the relationship object between those nodes
|
61
|
+
#
|
62
|
+
# ==== Returns
|
63
|
+
#
|
64
|
+
# Neo4j::Relationships::DeclRelationshipDsl
|
65
|
+
#
|
66
|
+
def has_one(rel_type, params = {})
|
67
|
+
clazz = self
|
68
|
+
|
69
|
+
|
70
|
+
module_eval(%Q{def #{rel_type}=(value)
|
71
|
+
dsl = #{clazz}.decl_relationships[:'#{rel_type.to_s}']
|
72
|
+
r = Neo4j::Mapping::HasN.new(self, dsl)
|
73
|
+
r.rels.each {|n| n.del} # delete previous relationships, only one can exist
|
74
|
+
r << value
|
75
|
+
r
|
76
|
+
end}, __FILE__, __LINE__)
|
77
|
+
|
78
|
+
module_eval(%Q{def #{rel_type}
|
79
|
+
dsl = #{clazz}.decl_relationships[:'#{rel_type.to_s}']
|
80
|
+
r = Neo4j::Mapping::HasN.new(self, dsl)
|
81
|
+
[*r][0]
|
82
|
+
end}, __FILE__, __LINE__)
|
83
|
+
|
84
|
+
module_eval(%Q{
|
85
|
+
def #{rel_type}_rel
|
86
|
+
dsl = #{clazz}.decl_relationships[:'#{rel_type.to_s}']
|
87
|
+
r = Neo4j::Mapping::HasN.new(self, dsl).rels
|
88
|
+
[*r][0]
|
89
|
+
end}, __FILE__, __LINE__)
|
90
|
+
|
91
|
+
decl_relationships[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, params)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Neo4j::Mapping
|
2
|
+
module ClassMethods
|
3
|
+
class Rules
|
4
|
+
class << self
|
5
|
+
def add(clazz, field, &block)
|
6
|
+
clazz = clazz.to_s
|
7
|
+
@rules ||= {}
|
8
|
+
@rules[clazz] ||= {}
|
9
|
+
filter = block.nil? ? Proc.new{|*| true} : block
|
10
|
+
@rules[clazz][field] = filter
|
11
|
+
end
|
12
|
+
|
13
|
+
def fields_for(clazz)
|
14
|
+
clazz = clazz.to_s
|
15
|
+
return [] if @rules.nil? || @rules[clazz].nil?
|
16
|
+
@rules[clazz].keys
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(clazz)
|
20
|
+
clazz = clazz.to_s
|
21
|
+
# delete the rule node if found
|
22
|
+
if Neo4j.ref_node.rel?(clazz)
|
23
|
+
Neo4j.ref_node.outgoing(clazz).each { |n| n.del }
|
24
|
+
end
|
25
|
+
@rules.delete(clazz) if @rules
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_neo4j_started(*)
|
29
|
+
create_rules if @rules
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_rules
|
33
|
+
@rules.each_key do |clazz|
|
34
|
+
# check if rule nodes exist, if note create them
|
35
|
+
if !Neo4j.ref_node.rel?(clazz)
|
36
|
+
Neo4j::Transaction.run do
|
37
|
+
node = Neo4j::Node.new
|
38
|
+
Neo4j.ref_node.outgoing(clazz) << node
|
39
|
+
node
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def trigger?(node)
|
47
|
+
@rules && node.property?(:_classname) && @rules.include?(node[:_classname])
|
48
|
+
end
|
49
|
+
|
50
|
+
def rule_for(clazz)
|
51
|
+
Neo4j.ref_node.outgoing(clazz).first
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def on_property_changed(node, key, old_value, new_value)
|
56
|
+
return unless trigger?(node)
|
57
|
+
clazz = node[:_classname]
|
58
|
+
return if @rules[clazz].nil?
|
59
|
+
agg_node = rule_for(node[:_classname])
|
60
|
+
@rules[clazz].each_pair do |field, filter|
|
61
|
+
if filter.call(node)
|
62
|
+
# is this node already included ?
|
63
|
+
if !node.rel?(field)
|
64
|
+
agg_node.outgoing(field) << node
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# remove old ?
|
68
|
+
node.rels(field).incoming.each { |x| x.del }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
module Aggregate
|
77
|
+
|
78
|
+
# Creates an rule node attached to the Neo4j.ref_node
|
79
|
+
# Can be used to rule all instances of a specific Ruby class.
|
80
|
+
#
|
81
|
+
# Example of usage:
|
82
|
+
# class Person
|
83
|
+
# include Neo4j
|
84
|
+
# rule :all
|
85
|
+
# rule :young { self[:age] < 10 }
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# p1 = Person.new :age => 5
|
89
|
+
# p2 = Person.new :age => 7
|
90
|
+
# p3 = Person.new :age => 12
|
91
|
+
# Neo4j::Transaction.finish
|
92
|
+
# Person.all # => [p1,p2,p3]
|
93
|
+
# Person.young # => [p1,p2]
|
94
|
+
# p1.young? # => true
|
95
|
+
#
|
96
|
+
def rule(name, &block)
|
97
|
+
singelton = class << self;
|
98
|
+
self;
|
99
|
+
end
|
100
|
+
|
101
|
+
# define class methods
|
102
|
+
singelton.send(:define_method, name) do
|
103
|
+
agg_node = Rules.rule_for(self)
|
104
|
+
raise "no rule node for #{name} on #{self}" if agg_node.nil?
|
105
|
+
traversal = agg_node.outgoing(name) # TODO possible to cache this object
|
106
|
+
Rules.fields_for(self).each do |filter_name|
|
107
|
+
traversal.filter_method(filter_name) do |path|
|
108
|
+
path.end_node.rel?(filter_name, :incoming)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
traversal
|
112
|
+
end
|
113
|
+
|
114
|
+
# define instance methods
|
115
|
+
self.send(:define_method, "#{name}?") do
|
116
|
+
instance_eval &block
|
117
|
+
end
|
118
|
+
|
119
|
+
Rules.add(self, name, &block)
|
120
|
+
end
|
121
|
+
|
122
|
+
# This is typically used for RSpecs to clean up rule nodes created by the #rule method.
|
123
|
+
# It also remove the given class method.
|
124
|
+
def delete_rules
|
125
|
+
singelton = class << self; self; end
|
126
|
+
Rules.fields_for(self).each do |name|
|
127
|
+
singelton.send(:remove_method, name)
|
128
|
+
end
|
129
|
+
Rules.delete(self)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
Neo4j.unstarted_db.event_handler.add(Rules)
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Neo4j::Mapping
|
2
|
+
|
3
|
+
|
4
|
+
# A DSL for declared relationships has_n and has_one
|
5
|
+
# This DSL will be used to create accessor methods for relationships.
|
6
|
+
# Instead of using the 'raw' Neo4j::NodeMixin#rels method where one needs to know
|
7
|
+
# the name of relationship and direction one can use the generated accessor methods.
|
8
|
+
#
|
9
|
+
# The DSL can also be used to specify a mapping to a Ruby class for a relationship, see Neo4j::Relationships::DeclRelationshipDsl#relationship
|
10
|
+
#
|
11
|
+
# ==== Example
|
12
|
+
#
|
13
|
+
# class Folder
|
14
|
+
# include Neo4j::NodeMixin
|
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::NodeMixin
|
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 DeclRelationshipDsl
|
34
|
+
|
35
|
+
attr_reader :to_type, :to_class, :cascade_delete_prop_name, :counter, :rel_id, :direction
|
36
|
+
CASCADE_DELETE_PROP_NAMES = {:outgoing => :_cascade_delete_outgoing, :incoming => :_cascade_delete_incoming}
|
37
|
+
|
38
|
+
def initialize(rel_id, params)
|
39
|
+
@direction = :outgoing
|
40
|
+
@rel_id = rel_id
|
41
|
+
@to_type = rel_id
|
42
|
+
@namespace_type = rel_id
|
43
|
+
@cascade_delete_prop_name = CASCADE_DELETE_PROP_NAMES[params[:cascade_delete]]
|
44
|
+
@counter = params[:counter] == true
|
45
|
+
end
|
46
|
+
|
47
|
+
# If a counter was specified in the dsl for counting number of nodes in this relationship.
|
48
|
+
#
|
49
|
+
def counter?
|
50
|
+
@counter
|
51
|
+
end
|
52
|
+
|
53
|
+
# If cascade delete was specified for this relationship
|
54
|
+
#
|
55
|
+
def cascade_delete?
|
56
|
+
!@cascade_delete_prop_name.nil?
|
57
|
+
end
|
58
|
+
|
59
|
+
def class_and_type_from_args(args) # :nodoc:
|
60
|
+
if (args.size > 1)
|
61
|
+
return args[0], args[1]
|
62
|
+
else
|
63
|
+
return args[0], @rel_id
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# The actual relationship type that this DSL will use
|
69
|
+
def namespace_type
|
70
|
+
@to_class.nil? ? @to_type.to_s : "#{@to_class.to_s}##{@to_type.to_s}"
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# Specifies an outgoing relationship.
|
75
|
+
# The name of the outgoing class will be used as a prefix for the relationship used.
|
76
|
+
#
|
77
|
+
# ==== Arguments
|
78
|
+
# clazz:: to which class this relationship goes
|
79
|
+
# relationship:: optional, the relationship to use
|
80
|
+
#
|
81
|
+
# ==== 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
|
+
def to(*args)
|
92
|
+
@direction = :outgoing
|
93
|
+
@to_class, @to_type = class_and_type_from_args(args)
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# Specifies an incoming relationship.
|
98
|
+
# Will use the outgoing relationship given by the from class.
|
99
|
+
#
|
100
|
+
# ==== Example
|
101
|
+
# class FolderNode
|
102
|
+
# include Neo4j::NodeMixin
|
103
|
+
# has_n(:files).to(FileNode)
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# class FileNode
|
107
|
+
# include Neo4j::NodeMixin
|
108
|
+
# has_one(:folder).from(FileNode, :files)
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# file = FileNode.new
|
112
|
+
# # create an outgoing relationship of type 'FileNode#files' from folder node to file
|
113
|
+
# file.folder = FolderNode.new
|
114
|
+
#
|
115
|
+
def from(*args)
|
116
|
+
#(clazz, type)
|
117
|
+
@direction = :incoming
|
118
|
+
@to_class, @to_type = class_and_type_from_args(args)
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
# Specifies which relationship ruby class to use for the relationship
|
123
|
+
#
|
124
|
+
# ==== Example
|
125
|
+
#
|
126
|
+
# class OrderLine
|
127
|
+
# include Neo4j::RelationshipMixin
|
128
|
+
# property :units
|
129
|
+
# property :unit_price
|
130
|
+
# end
|
131
|
+
#
|
132
|
+
# class Order
|
133
|
+
# property :total_cost
|
134
|
+
# property :dispatched
|
135
|
+
# has_n(:products).to(Product).relationship(OrderLine)
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# order = Order.new
|
139
|
+
# order.products << Product.new
|
140
|
+
# order.products_rels.first # => OrderLine
|
141
|
+
#
|
142
|
+
def relationship(rel_class)
|
143
|
+
@relationship = rel_class
|
144
|
+
self
|
145
|
+
end
|
146
|
+
|
147
|
+
def relationship_class # :nodoc:
|
148
|
+
@relationship
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|