neo4j 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/CHANGELOG +141 -0
  2. data/CONTRIBUTORS +15 -0
  3. data/Gemfile +3 -0
  4. data/README.rdoc +2015 -0
  5. data/lib/neo4j.old/batch_inserter.rb +144 -0
  6. data/lib/neo4j.old/config.rb +138 -0
  7. data/lib/neo4j.old/event_handler.rb +73 -0
  8. data/lib/neo4j.old/extensions/activemodel.rb +158 -0
  9. data/lib/neo4j.old/extensions/aggregate.rb +12 -0
  10. data/lib/neo4j.old/extensions/aggregate/aggregate_enum.rb +40 -0
  11. data/lib/neo4j.old/extensions/aggregate/ext/node_mixin.rb +69 -0
  12. data/lib/neo4j.old/extensions/aggregate/node_aggregate.rb +8 -0
  13. data/lib/neo4j.old/extensions/aggregate/node_aggregate_mixin.rb +331 -0
  14. data/lib/neo4j.old/extensions/aggregate/node_aggregator.rb +216 -0
  15. data/lib/neo4j.old/extensions/aggregate/node_group.rb +43 -0
  16. data/lib/neo4j.old/extensions/aggregate/prop_group.rb +30 -0
  17. data/lib/neo4j.old/extensions/aggregate/property_enum.rb +24 -0
  18. data/lib/neo4j.old/extensions/aggregate/props_aggregate.rb +8 -0
  19. data/lib/neo4j.old/extensions/aggregate/props_aggregate_mixin.rb +31 -0
  20. data/lib/neo4j.old/extensions/aggregate/props_aggregator.rb +80 -0
  21. data/lib/neo4j.old/extensions/find_path.rb +117 -0
  22. data/lib/neo4j.old/extensions/graph_algo.rb +1 -0
  23. data/lib/neo4j.old/extensions/graph_algo/all_simple_paths.rb +133 -0
  24. data/lib/neo4j.old/extensions/graph_algo/neo4j-graph-algo-0.3.jar +0 -0
  25. data/lib/neo4j.old/extensions/reindexer.rb +104 -0
  26. data/lib/neo4j.old/extensions/rest.rb +21 -0
  27. data/lib/neo4j.old/extensions/rest/rest.rb +336 -0
  28. data/lib/neo4j.old/extensions/rest/rest_mixin.rb +193 -0
  29. data/lib/neo4j.old/extensions/rest/server.rb +50 -0
  30. data/lib/neo4j.old/extensions/rest/stubs.rb +141 -0
  31. data/lib/neo4j.old/extensions/rest_master.rb +34 -0
  32. data/lib/neo4j.old/extensions/rest_slave.rb +31 -0
  33. data/lib/neo4j.old/extensions/tx_tracker.rb +392 -0
  34. data/lib/neo4j.old/indexer.rb +187 -0
  35. data/lib/neo4j.old/jars.rb +6 -0
  36. data/lib/neo4j.old/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  37. data/lib/neo4j.old/jars/neo4j-kernel-1.0.jar +0 -0
  38. data/lib/neo4j.old/mixins/java_list_mixin.rb +139 -0
  39. data/lib/neo4j.old/mixins/java_node_mixin.rb +205 -0
  40. data/lib/neo4j.old/mixins/java_property_mixin.rb +169 -0
  41. data/lib/neo4j.old/mixins/java_relationship_mixin.rb +60 -0
  42. data/lib/neo4j.old/mixins/migration_mixin.rb +157 -0
  43. data/lib/neo4j.old/mixins/node_mixin.rb +249 -0
  44. data/lib/neo4j.old/mixins/property_class_methods.rb +265 -0
  45. data/lib/neo4j.old/mixins/rel_class_methods.rb +167 -0
  46. data/lib/neo4j.old/mixins/relationship_mixin.rb +103 -0
  47. data/lib/neo4j.old/neo.rb +247 -0
  48. data/lib/neo4j.old/node.rb +49 -0
  49. data/lib/neo4j.old/reference_node.rb +15 -0
  50. data/lib/neo4j.old/relationship.rb +85 -0
  51. data/lib/neo4j.old/relationships/decl_relationship_dsl.rb +164 -0
  52. data/lib/neo4j.old/relationships/has_list.rb +101 -0
  53. data/lib/neo4j.old/relationships/has_n.rb +129 -0
  54. data/lib/neo4j.old/relationships/node_traverser.rb +138 -0
  55. data/lib/neo4j.old/relationships/relationship_dsl.rb +149 -0
  56. data/lib/neo4j.old/relationships/traversal_position.rb +50 -0
  57. data/lib/neo4j.old/relationships/wrappers.rb +51 -0
  58. data/lib/neo4j.old/search_result.rb +72 -0
  59. data/lib/neo4j.old/transaction.rb +254 -0
  60. data/lib/neo4j.old/version.rb +3 -0
  61. data/lib/neo4j.rb +50 -0
  62. data/lib/neo4j/config.rb +137 -0
  63. data/lib/neo4j/database.rb +43 -0
  64. data/lib/neo4j/equal.rb +22 -0
  65. data/lib/neo4j/event_handler.rb +91 -0
  66. data/lib/neo4j/index.rb +157 -0
  67. data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  68. data/lib/neo4j/jars/lucene-core-2.9.2.jar +0 -0
  69. data/lib/neo4j/jars/lucene-core-3.0.1.jar +0 -0
  70. data/lib/neo4j/jars/neo4j-index-1.1.jar +0 -0
  71. data/lib/neo4j/jars/neo4j-kernel-1.1.1.jar +0 -0
  72. data/lib/neo4j/jars/neo4j-kernel-1.1.jar +0 -0
  73. data/lib/neo4j/jars/neo4j-lucene-index-0.1-20100916.085626-67.jar +0 -0
  74. data/lib/neo4j/mapping/class_methods/index.rb +21 -0
  75. data/lib/neo4j/mapping/class_methods/property.rb +139 -0
  76. data/lib/neo4j/mapping/class_methods/relationship.rb +96 -0
  77. data/lib/neo4j/mapping/class_methods/rule.rb +135 -0
  78. data/lib/neo4j/mapping/decl_relationship_dsl.rb +151 -0
  79. data/lib/neo4j/mapping/has_n.rb +117 -0
  80. data/lib/neo4j/mapping/node_mixin.rb +70 -0
  81. data/lib/neo4j/neo4j.rb +65 -0
  82. data/lib/neo4j/node.rb +82 -0
  83. data/lib/neo4j/node_mixin.rb +4 -0
  84. data/lib/neo4j/node_relationship.rb +60 -0
  85. data/lib/neo4j/node_traverser.rb +141 -0
  86. data/lib/neo4j/property.rb +72 -0
  87. data/lib/neo4j/rails/lucene_connection_closer.rb +19 -0
  88. data/lib/neo4j/rails/model.rb +210 -0
  89. data/lib/neo4j/rails/railtie.rb +16 -0
  90. data/lib/neo4j/rails/transaction.rb +29 -0
  91. data/lib/neo4j/rails/value.rb +43 -0
  92. data/lib/neo4j/relationship.rb +88 -0
  93. data/lib/neo4j/relationship_traverser.rb +57 -0
  94. data/lib/neo4j/to_java.rb +17 -0
  95. data/lib/neo4j/transaction.rb +69 -0
  96. data/lib/neo4j/version.rb +3 -0
  97. data/neo4j.gemspec +30 -0
  98. metadata +243 -0
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