neo4j 1.0.0.beta.11 → 1.0.0.beta.12

Sign up to get free protection for your applications and to get access to all the features.
data/lib/neo4j.rb CHANGED
@@ -50,6 +50,8 @@ require 'neo4j/rails/model'
50
50
  require 'neo4j/rails/value'
51
51
  require 'neo4j/rails/lucene_connection_closer'
52
52
 
53
+ require 'neo4j/model'
54
+
53
55
 
54
56
 
55
57
  # hmm, looks like Enumerator have been moved in some ruby versions
@@ -2,6 +2,7 @@ module Neo4j::Mapping
2
2
  module ClassMethods
3
3
 
4
4
  module Relationship
5
+ include Neo4j::ToJava
5
6
 
6
7
  # Specifies a relationship between two node classes.
7
8
  # Generates assignment and accessor methods for the given relationship.
@@ -24,9 +25,9 @@ module Neo4j::Mapping
24
25
  def has_n(rel_type, params = {})
25
26
  clazz = self
26
27
  module_eval(%Q{
27
- def #{rel_type}(&block)
28
+ def #{rel_type}
28
29
  dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
29
- Neo4j::Mapping::HasN.new(self, dsl, &block)
30
+ Neo4j::Mapping::HasN.new(self, dsl)
30
31
  end}, __FILE__, __LINE__)
31
32
 
32
33
  module_eval(%Q{
@@ -61,28 +62,25 @@ module Neo4j::Mapping
61
62
  #
62
63
  def has_one(rel_type, params = {})
63
64
  clazz = self
64
-
65
-
66
65
  module_eval(%Q{def #{rel_type}=(value)
67
- dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
68
- r = Neo4j::Mapping::HasN.new(self, dsl)
69
- r.rels.each {|n| n.del} # delete previous relationships, only one can exist
70
- r << value
71
- r
72
- end}, __FILE__, __LINE__)
66
+ dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
67
+ rel = dsl.single_relationship(self)
68
+ rel.del unless rel.nil?
69
+ dsl.create_relationship_to(self, value)
70
+ end}, __FILE__, __LINE__)
73
71
 
74
72
  module_eval(%Q{def #{rel_type}
75
- dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
76
- r = Neo4j::Mapping::HasN.new(self, dsl)
77
- [*r][0]
78
- end}, __FILE__, __LINE__)
73
+ dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
74
+ dsl.single_relationship(self)
75
+ end}, __FILE__, __LINE__)
79
76
 
77
+ # TODO
80
78
  module_eval(%Q{
81
- def #{rel_type}_rel
82
- dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
83
- r = Neo4j::Mapping::HasN.new(self, dsl).rels
84
- [*r][0]
85
- end}, __FILE__, __LINE__)
79
+ def #{rel_type}_rel
80
+ dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
81
+ r = Neo4j::Mapping::HasN.new(self, dsl).rels
82
+ [*r][0]
83
+ end}, __FILE__, __LINE__)
86
84
 
87
85
  _decl_rels[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, true, params)
88
86
  end
@@ -31,6 +31,7 @@ module Neo4j::Mapping
31
31
  # <b>File#folder</b> :: for accessing nodes from relationship 'files' from the outgoing Folder node
32
32
  #
33
33
  class DeclRelationshipDsl
34
+ include Neo4j::ToJava
34
35
 
35
36
  attr_reader :to_type, :to_class, :cascade_delete_prop_name, :counter, :rel_id, :direction
36
37
  CASCADE_DELETE_PROP_NAMES = {:outgoing => :_cascade_delete_outgoing, :incoming => :_cascade_delete_incoming}
@@ -75,6 +76,41 @@ module Neo4j::Mapping
75
76
  @to_class.nil? ? @to_type.to_s : "#{@to_class.to_s}##{@to_type.to_s}"
76
77
  end
77
78
 
79
+ def each_node(node, direction, &block)
80
+ type = type_to_java(namespace_type)
81
+ dir = dir_to_java(direction)
82
+ node._java_node.getRelationships(type, dir).each do |rel|
83
+ other = rel.getOtherNode(node).wrapper
84
+ block.call other
85
+ end
86
+ end
87
+
88
+ def single_relationship(node)
89
+ type = type_to_java(namespace_type)
90
+ dir = dir_to_java(@direction)
91
+ rel = node._java_node.getSingleRelationship(type, dir)
92
+ rel.nil? ? nil : rel.end_node.wrapper
93
+ end
94
+
95
+ def create_relationship_to(node, other)
96
+ # If the are creating an incoming relationship we need to swap incoming and outgoing nodes
97
+ if @direction == :outgoing
98
+ from, to = node, other
99
+ else
100
+ from, to = other, node
101
+ end
102
+
103
+ java_type = type_to_java(namespace_type)
104
+ rel = from._java_node.create_relationship_to(to._java_node, java_type)
105
+ rel[:_classname] = relationship_class.to_s if relationship_class
106
+
107
+ # TODO - not implemented yet
108
+ # the from.neo_id is only used for cascade_delete_incoming since that node will be deleted when all the list items has been deleted.
109
+ # if cascade_delete_outgoing all nodes will be deleted when the root node is deleted
110
+ # if cascade_delete_incoming then the root node will be deleted when all root nodes' outgoing nodes are deleted
111
+ #rel[@dsl.cascade_delete_prop_name] = node.neo_id if @dsl.cascade_delete?
112
+ rel.wrapper
113
+ end
78
114
 
79
115
  # Specifies an outgoing relationship.
80
116
  # The name of the outgoing class will be used as a prefix for the relationship used.
@@ -11,7 +11,7 @@ module Neo4j
11
11
  def initialize(node, dsl) # :nodoc:
12
12
  @node = node
13
13
  @direction = dsl.direction
14
- # returns the other DSL if it exists otherwise use this DSL for specifing incoming relationships
14
+ # returns the other DSL if it exists otherwise use this DSL for specifying incoming relationships
15
15
  if @direction == :outgoing
16
16
  @dsl = dsl
17
17
  else
@@ -20,8 +20,10 @@ module Neo4j
20
20
  @dsl = clazz._decl_rels[dsl.to_type]
21
21
  raise "Unspecified outgoing relationship '#{dsl.to_type}' for incoming relationship '#{dsl.rel_id}' on class #{clazz}" if @dsl.nil?
22
22
  end
23
+ end
23
24
 
24
- @traverser = Neo4j::NodeTraverser.new(node._java_node, @dsl.namespace_type, @direction)
25
+ def to_s
26
+ "HasN [#@direction, #{@node.neo_id} #{@dsl.namespace_type}]"
25
27
  end
26
28
 
27
29
  def size
@@ -41,6 +43,12 @@ module Neo4j
41
43
  super
42
44
  end
43
45
 
46
+ # Required by the Enumerable mixin.
47
+ def each(&block)
48
+ @dsl.each_node(@node, @direction, &block)
49
+ end
50
+
51
+
44
52
  # Returns the relationships instead of the nodes.
45
53
  #
46
54
  # ==== Example
@@ -51,39 +59,16 @@ module Neo4j
51
59
  Neo4j::RelationshipTraverser.new(@node._java_node, [@dsl.namespace_type], @direction)
52
60
  end
53
61
 
54
- # Sets the depth of the traversal.
55
- # Default is 1 if not specified.
56
- #
57
- # ==== Example
58
- # morpheus.friends.depth(:all).each { ... }
59
- # morpheus.friends.depth(3).each { ... }
60
- #
61
- # ==== Arguments
62
- # d:: the depth or :all if traversing to the end of the network (symbol or fixnum)
63
- # ==== Return
64
- # self
65
- #
66
- def depth(d)
67
- @traverser.depth(d)
68
- self
69
- end
70
-
71
- # Required by the Enumerable mixin.
72
- def each(&block)
73
- @traverser.each(&block)
74
- end
75
-
76
-
77
62
  # Returns true if there are no node in this type of relationship
78
63
  def empty?
79
- @traverser.empty?
64
+ first != nil
80
65
  end
81
66
 
82
67
 
83
68
  # Creates a relationship instance between this and the other node.
84
69
  # Returns the relationship object
85
70
  def new(other)
86
- create_rel(@node, other)
71
+ @dsl.create_relationship_to(@node, other)
87
72
  end
88
73
 
89
74
 
@@ -101,31 +86,9 @@ module Neo4j
101
86
  # self
102
87
  #
103
88
  def <<(other)
104
- create_rel(@node, other)
89
+ @dsl.create_relationship_to(@node, other)
105
90
  self
106
91
  end
107
-
108
-
109
- def create_rel(node, other) # :nodoc:
110
- # If the are creating an incoming relationship we need to swap incoming and outgoing nodes
111
- if @direction == :outgoing
112
- from, to = node, other
113
- else
114
- from, to = other, node
115
- end
116
-
117
- java_type = type_to_java(@dsl.namespace_type)
118
- rel = from._java_node.create_relationship_to(to._java_node, java_type)
119
- rel[:_classname] = @dsl.relationship_class.to_s if @dsl.relationship_class
120
-
121
- # TODO - not implemented yet
122
- # the from.neo_id is only used for cascade_delete_incoming since that node will be deleted when all the list items has been deleted.
123
- # if cascade_delete_outgoing all nodes will be deleted when the root node is deleted
124
- # if cascade_delete_incoming then the root node will be deleted when all root nodes' outgoing nodes are deleted
125
- #rel[@dsl.cascade_delete_prop_name] = node.neo_id if @dsl.cascade_delete?
126
- rel.wrapper
127
- end
128
-
129
92
  end
130
93
 
131
94
  end
@@ -6,7 +6,7 @@ module Neo4j::Mapping
6
6
 
7
7
  def_delegators :@_java_node, :[]=, :[], :property?, :props, :attributes, :update, :neo_id, :id, :rels, :rel?, :to_param, :getId,
8
8
  :rel, :del, :list?, :print, :print_sub, :outgoing, :incoming, :both,
9
- :equal?, :eql?, :==, :exist?, :getRelationships
9
+ :equal?, :eql?, :==, :exist?, :getRelationships, :getSingleRelationship
10
10
 
11
11
 
12
12
  # --------------------------------------------------------------------------
@@ -40,6 +40,10 @@ module Neo4j::Mapping
40
40
  end
41
41
 
42
42
 
43
+ def wrapper
44
+ self
45
+ end
46
+
43
47
  def self.included(c) # :nodoc:
44
48
  c.instance_eval do
45
49
  class << self
@@ -0,0 +1,4 @@
1
+ module Neo4j
2
+ # make an alias so that we don't have to write the long name Neo4j::Rails::Model
3
+ Model = Neo4j::Rails::Model
4
+ end
@@ -132,10 +132,7 @@ module Neo4j
132
132
  end
133
133
 
134
134
  def each
135
- iter = iterator
136
- while (iter.hasNext) do
137
- yield iter.next.wrapper
138
- end
135
+ iterator.each {|i| yield i.wrapper}
139
136
  end
140
137
 
141
138
  def iterator
@@ -147,7 +144,7 @@ module Neo4j
147
144
  end
148
145
  end
149
146
  @td = @td.prune(org.neo4j.kernel.Traversal.pruneAfterDepth( @depth ) ) unless @depth == :all
150
- @td.traverse(@from).nodes.iterator
147
+ @td.traverse(@from).nodes
151
148
  end
152
149
  end
153
150
 
@@ -1,358 +1,343 @@
1
- class Neo4j::Model
2
- include Neo4j::NodeMixin
3
- include ActiveModel::Validations
4
- include ActiveModel::Dirty
5
- include ActiveModel::MassAssignmentSecurity
1
+ module Neo4j
2
+ module Rails
3
+ class Model
4
+ include Neo4j::NodeMixin
5
+ include ActiveModel::Validations
6
+ include ActiveModel::Dirty
7
+ include ActiveModel::MassAssignmentSecurity
6
8
 
7
- extend ActiveModel::Naming
8
- extend ActiveModel::Callbacks
9
- extend Neo4j::Validations::ClassMethods
10
- extend Neo4j::TxMethods
9
+ extend ActiveModel::Naming
10
+ extend ActiveModel::Callbacks
11
+ extend Neo4j::Validations::ClassMethods
12
+ extend TxMethods
13
+ # extend ClassMethods::Relationship
11
14
 
12
- define_model_callbacks :create, :save, :update, :destroy
15
+ define_model_callbacks :create, :save, :update, :destroy
13
16
 
14
17
 
15
- UniquenessValidator = Neo4j::Validations::UniquenessValidator
18
+ UniquenessValidator = Neo4j::Validations::UniquenessValidator
16
19
 
17
- class RecordInvalidError < RuntimeError
18
- attr_reader :record
20
+ class RecordInvalidError < RuntimeError
21
+ attr_reader :record
19
22
 
20
- def initialize(record)
21
- @record = record
22
- super(@record.errors.full_messages.join(", "))
23
- end
24
- end
23
+ def initialize(record)
24
+ @record = record
25
+ super(@record.errors.full_messages.join(", "))
26
+ end
27
+ end
25
28
 
26
- # --------------------------------------
27
- # Initialize
28
- # --------------------------------------
29
+ # --------------------------------------
30
+ # Initialize
31
+ # --------------------------------------
29
32
 
30
- def initialize(*)
31
- end
33
+ def initialize(*)
34
+ end
32
35
 
33
- def init_on_create(*args) # :nodoc:
34
- super()
35
- self.attributes=args[0] if args[0].respond_to?(:each_pair)
36
- @_created_record = true
37
- end
36
+ def init_on_create(*args) # :nodoc:
37
+ super()
38
+ self.attributes=args[0] if args[0].respond_to?(:each_pair)
39
+ @_created_record = true
40
+ end
38
41
 
39
- # --------------------------------------
40
- # Identity
41
- # --------------------------------------
42
+ # --------------------------------------
43
+ # Identity
44
+ # --------------------------------------
42
45
 
43
- def id
44
- neo_id.nil? ? nil : neo_id.to_s
45
- end
46
+ def id
47
+ neo_id.nil? ? nil : neo_id.to_s
48
+ end
46
49
 
47
- def to_param
48
- persisted? ? neo_id.to_s : nil
49
- end
50
+ def to_param
51
+ persisted? ? neo_id.to_s : nil
52
+ end
50
53
 
51
- # Returns an Enumerable of all (primary) key attributes
52
- # or nil if model.persisted? is false
53
- def to_key
54
- persisted? ? [:id] : nil
55
- end
54
+ # Returns an Enumerable of all (primary) key attributes
55
+ # or nil if model.persisted? is false
56
+ def to_key
57
+ persisted? ? [:id] : nil
58
+ end
56
59
 
57
60
 
58
- # enables ActiveModel::Dirty and Validation
59
- def method_missing(method_id, *args, &block)
60
- if !self.class.attribute_methods_generated?
61
- self.class.define_attribute_methods(self.class._decl_props.keys)
62
- # try again
63
- send(method_id, *args, &block)
64
- end
65
- end
66
-
67
- # redefine this methods so that ActiveModel::Dirty will work
68
- def []=(key, new_value)
69
- key = key.to_s
70
- unless key[0] == ?_
71
- old_value = self.send(:[], key)
72
- attribute_will_change!(key) unless old_value == new_value
73
- end
74
- Neo4j::Rails::Transaction.running? ? super : Neo4j::Rails::Transaction.run { super }
75
- end
61
+ # enables ActiveModel::Dirty and Validation
62
+ def method_missing(method_id, *args, &block)
63
+ if !self.class.attribute_methods_generated?
64
+ self.class.define_attribute_methods(self.class._decl_props.keys)
65
+ # try again
66
+ send(method_id, *args, &block)
67
+ end
68
+ end
76
69
 
77
- def attribute_will_change!(attr)
78
- begin
79
- value = __send__(:[], attr)
80
- value = value.duplicable? ? value.clone : value
81
- rescue TypeError, NoMethodError
82
- end
83
- changed_attributes[attr] = value
84
- end
70
+ # redefine this methods so that ActiveModel::Dirty will work
71
+ def []=(key, new_value)
72
+ key = key.to_s
73
+ unless key[0] == ?_
74
+ old_value = self.send(:[], key)
75
+ attribute_will_change!(key) unless old_value == new_value
76
+ end
77
+ Neo4j::Rails::Transaction.running? ? super : Neo4j::Rails::Transaction.run { super }
78
+ end
85
79
 
80
+ def attribute_will_change!(attr)
81
+ begin
82
+ value = __send__(:[], attr)
83
+ value = value.duplicable? ? value.clone : value
84
+ rescue TypeError, NoMethodError
85
+ end
86
+ changed_attributes[attr] = value
87
+ end
86
88
 
87
- def read_attribute_for_validation(key)
88
- respond_to?(key) ? send(key) : self[key]
89
- end
90
89
 
91
- def attributes=(values)
92
- sanitize_for_mass_assignment(values).each do |k, v|
93
- if respond_to?("#{k}=")
94
- send("#{k}=", v)
95
- else
96
- self[k] = v
90
+ def read_attribute_for_validation(key)
91
+ respond_to?(key) ? send(key) : self[key]
97
92
  end
98
- end
99
- end
100
93
 
94
+ def attributes=(values)
95
+ sanitize_for_mass_assignment(values).each do |k, v|
96
+ if respond_to?("#{k}=")
97
+ send("#{k}=", v)
98
+ else
99
+ self[k] = v
100
+ end
101
+ end
102
+ end
101
103
 
102
- # Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved.
103
- # If saving fails because the resource is invalid then false will be returned.
104
- def update_attributes(attributes)
105
- self.attributes=attributes
106
- save
107
- end
108
104
 
109
- def update_attributes!(attributes)
110
- self.attributes=attributes
111
- save!
112
- end
105
+ # Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved.
106
+ # If saving fails because the resource is invalid then false will be returned.
107
+ def update_attributes(attributes)
108
+ self.attributes=attributes
109
+ save
110
+ end
113
111
 
114
- def update_nested_attributes(rel_type, clazz, has_one, attr, options)
115
- allow_destroy,reject_if = [options[:allow_destroy], options[:reject_if]] if options
116
-
117
- if new?
118
- # We are updating a node that was created with the 'new' method.
119
- # The relationship will only be kept in the Value object.
120
- outgoing(rel_type)<<clazz.new(attr) unless reject_if?(reject_if,attr)
121
- else
122
- # We have a node that was created with the #create method - has real Neo4j relationships
123
- # does it exist ?
124
- found = if has_one
125
- # id == nil that means we have a has_one relationship
126
- outgoing(rel_type).first
127
- else
128
- # do we have an ID ?
129
- id = attr[:id]
130
- # this is a has_n relationship, find which one we want to update
131
- id && outgoing(rel_type).find { |n| n.id == id }
132
- end
112
+ def update_attributes!(attributes)
113
+ self.attributes=attributes
114
+ save!
115
+ end
133
116
 
134
- # Check if we want to destroy not found nodes (e.g. {..., :_destroy => '1' } ?
135
- destroy = attr[:_destroy] && attr[:_destroy] != '0'
117
+ def update_nested_attributes(rel_type, clazz, has_one, attr, options)
118
+ allow_destroy, reject_if = [options[:allow_destroy], options[:reject_if]] if options
136
119
 
137
- if found
138
- if destroy
139
- found.destroy if allow_destroy
120
+ if new?
121
+ # We are updating a node that was created with the 'new' method.
122
+ # The relationship will only be kept in the Value object.
123
+ outgoing(rel_type)<<clazz.new(attr) unless reject_if?(reject_if, attr)
140
124
  else
141
- found.update_attributes_in_tx(attr) # it already exist, so update that one
125
+ # We have a node that was created with the #create method - has real Neo4j relationships
126
+ # does it exist ?
127
+ found = if has_one
128
+ # id == nil that means we have a has_one relationship
129
+ outgoing(rel_type).first
130
+ else
131
+ # do we have an ID ?
132
+ id = attr[:id]
133
+ # this is a has_n relationship, find which one we want to update
134
+ id && outgoing(rel_type).find { |n| n.id == id }
135
+ end
136
+
137
+ # Check if we want to destroy not found nodes (e.g. {..., :_destroy => '1' } ?
138
+ destroy = attr[:_destroy] && attr[:_destroy] != '0'
139
+
140
+ puts "FOUND #{found}"
141
+ if found
142
+ if destroy
143
+ found.destroy if allow_destroy
144
+ else
145
+ found.update_attributes_in_tx(attr) # it already exist, so update that one
146
+ end
147
+ elsif !destroy && !reject_if?(reject_if, attr)
148
+ new_node = clazz.new(attr)
149
+ saved = new_node.save
150
+ outgoing(rel_type) << new_node if saved
151
+ end
142
152
  end
143
- elsif !destroy && !reject_if?(reject_if,attr)
144
- new_node = clazz.new(attr)
145
- saved = new_node.save
146
- outgoing(rel_type) << new_node if saved
147
153
  end
148
- end
149
- end
150
-
151
- def reject_if?(proc_or_symbol, attr)
152
- return false if proc_or_symbol.nil?
153
- if proc_or_symbol.is_a?(Symbol)
154
- meth = method(proc_or_symbol)
155
- meth.arity == 0 ? meth.call : meth.call(attr)
156
- else
157
- proc_or_symbol.call(attr)
158
- end
159
- end
160
-
161
- def delete
162
- super
163
- @_deleted = true
164
- @_persisted = false
165
- end
166
154
 
167
- def save
168
- valid = valid?
169
- if valid
170
- # if we are trying to save a value then we should create a real node
171
- valid = _run_save_callbacks { create_or_update_node }
172
- @_created_record = false
173
- true
174
- else
175
- # if not valid we should rollback the transaction so that the changes does not take place.
176
- # no point failing the transaction if we have created a model with 'new'
177
- Neo4j::Rails::Transaction.fail if Neo4j::Rails::Transaction.running? && !_java_node.kind_of?(Neo4j::Value)
178
- false
179
- end
180
- valid
181
- end
155
+ def reject_if?(proc_or_symbol, attr)
156
+ return false if proc_or_symbol.nil?
157
+ if proc_or_symbol.is_a?(Symbol)
158
+ meth = method(proc_or_symbol)
159
+ meth.arity == 0 ? meth.call : meth.call(attr)
160
+ else
161
+ proc_or_symbol.call(attr)
162
+ end
163
+ end
182
164
 
183
- def create_or_update_node
184
- valid = true
185
- if _java_node.kind_of?(Neo4j::Value)
186
- node = Neo4j::Node.new(props)
187
- valid = _java_node.save_nested(node)
188
- init_on_load(node)
189
- init_on_create
190
- end
165
+ def delete
166
+ super
167
+ @_deleted = true
168
+ @_persisted = false
169
+ end
191
170
 
192
- if new_record?
193
- _run_create_callbacks { clear_changes }
194
- else
195
- _run_update_callbacks { clear_changes }
196
- end
197
- valid
198
- end
171
+ def save
172
+ valid = valid?
173
+ if valid
174
+ # if we are trying to save a value then we should create a real node
175
+ valid = _run_save_callbacks { create_or_update_node }
176
+ @_created_record = false
177
+ true
178
+ else
179
+ # if not valid we should rollback the transaction so that the changes does not take place.
180
+ # no point failing the transaction if we have created a model with 'new'
181
+ Neo4j::Rails::Transaction.fail if Neo4j::Rails::Transaction.running? && !_java_node.kind_of?(Neo4j::Rails::Value)
182
+ false
183
+ end
184
+ valid
185
+ end
199
186
 
200
- def clear_changes
201
- @previously_changed = changes
202
- @changed_attributes.clear
203
- end
187
+ def create_or_update_node
188
+ valid = true
189
+ if _java_node.kind_of?(Neo4j::Rails::Value)
190
+ node = Neo4j::Node.new(props)
191
+ valid = _java_node.save_nested(node)
192
+ init_on_load(node)
193
+ init_on_create
194
+ end
204
195
 
205
- def save!
206
- raise RecordInvalidError.new(self) unless save
207
- end
196
+ if new_record?
197
+ _run_create_callbacks { clear_changes }
198
+ else
199
+ _run_update_callbacks { clear_changes }
200
+ end
201
+ valid
202
+ end
208
203
 
209
- # Returns if the record is persisted, i.e. it’s not a new record and it was not destroyed
210
- def persisted?
211
- !new_record? && !destroyed?
212
- end
204
+ def clear_changes
205
+ @previously_changed = changes
206
+ @changed_attributes.clear
207
+ end
213
208
 
214
- def to_model
215
- self
216
- end
209
+ def save!
210
+ raise RecordInvalidError.new(self) unless save
211
+ end
217
212
 
218
- # Returns true if this object hasn’t been saved yet that is, a record for the object doesn’t exist yet; otherwise, returns false.
219
- def new_record?()
220
- # it is new if the model has been created with either the new or create method
221
- new? || @_created_record == true
222
- end
213
+ # Returns if the record is persisted, i.e. it’s not a new record and it was not destroyed
214
+ def persisted?
215
+ !new_record? && !destroyed?
216
+ end
223
217
 
224
- def new?
225
- _java_node.kind_of?(Neo4j::Value)
226
- end
218
+ def to_model
219
+ self
220
+ end
227
221
 
228
- def del
229
- @_deleted = true
230
- super
231
- end
222
+ # Returns true if this object hasn’t been saved yet — that is, a record for the object doesn’t exist yet; otherwise, returns false.
223
+ def new_record?()
224
+ # it is new if the model has been created with either the new or create method
225
+ new? || @_created_record == true
226
+ end
232
227
 
233
- def destroy
234
- _run_update_callbacks { del }
235
- end
228
+ def new?
229
+ _java_node.kind_of?(Neo4j::Rails::Value)
230
+ end
236
231
 
237
- def destroyed?()
238
- @_deleted
239
- end
232
+ def del
233
+ @_deleted = true
234
+ super
235
+ end
240
236
 
241
- tx_methods :destroy, :create_or_update_node, :update_attributes, :update_attributes!
237
+ def destroy
238
+ _run_update_callbacks { del }
239
+ end
242
240
 
243
- # --------------------------------------
244
- # Class Methods
245
- # --------------------------------------
241
+ def destroyed?()
242
+ @_deleted
243
+ end
246
244
 
247
- class << self
248
- extend Neo4j::TxMethods
245
+ tx_methods :destroy, :create_or_update_node, :update_attributes, :update_attributes!
249
246
 
250
- # returns a value object instead of creating a new node
251
- def new(*args)
252
- value = Neo4j::Value.new
253
- wrapped = self.orig_new
254
- wrapped.init_on_load(value)
255
- wrapped.attributes=args[0] if args[0].respond_to?(:each_pair)
247
+ # --------------------------------------
248
+ # Class Methods
249
+ # --------------------------------------
256
250
 
257
- wrapped.class._decl_rels.each_pair do |field, dsl|
251
+ class << self
252
+ extend TxMethods
258
253
 
259
- meta = class << wrapped;
260
- self;
254
+ # returns a value object instead of creating a new node
255
+ def new(*args)
256
+ wrapped = self.orig_new
257
+ value = Neo4j::Rails::Value.new(wrapped)
258
+ wrapped.init_on_load(value)
259
+ wrapped.attributes=args[0] if args[0].respond_to?(:each_pair)
260
+ wrapped
261
261
  end
262
262
 
263
- wrapped.class._decl_rels.each_pair do |field, dsl|
264
- meta.send(:define_method, field) do
265
- if new?
266
- value.outgoing(dsl.namespace_type)
267
- else
268
- self.outgoing(dsl.namespace_type)
269
- end
270
- end if dsl.direction == :outgoing
271
-
272
- meta.send(:define_method, field) do
273
- raise "NOT IMPLEMENTED #{field} (incoming relationship) FOR #new method, please create a new model with the create method instead"
274
- end if dsl.direction == :incoming
263
+ # Handle Model.find(params[:id])
264
+ def find(*args)
265
+ if args.length == 1 && String === args[0] && args[0].to_i != 0
266
+ load(*args)
267
+ else
268
+ hits = super
269
+ # We need to save this so that the Rack Neo4j::Rails:LuceneConnection::Closer can close it
270
+ Thread.current[:neo4j_lucene_connection] ||= []
271
+ Thread.current[:neo4j_lucene_connection] << hits
272
+ hits
273
+ end
275
274
  end
276
- end
277
-
278
- wrapped
279
- end
280
275
 
281
- # Handle Model.find(params[:id])
282
- def find(*args)
283
- if args.length == 1 && String === args[0] && args[0].to_i != 0
284
- load(*args)
285
- else
286
- hits = super
287
- # We need to save this so that the Rack Neo4j::Rails:LuceneConnection::Closer can close it
288
- Thread.current[:neo4j_lucene_connection] ||= []
289
- Thread.current[:neo4j_lucene_connection] << hits
290
- hits
291
- end
292
- end
293
-
294
- def load(*ids)
295
- result = ids.map { |id| Neo4j::Node.load(id) }
296
- if ids.length == 1
297
- result.first
298
- else
299
- result
300
- end
301
- end
276
+ def load(*ids)
277
+ result = ids.map { |id| Neo4j::Node.load(id) }
278
+ if ids.length == 1
279
+ result.first
280
+ else
281
+ result
282
+ end
283
+ end
302
284
 
303
285
 
304
- alias_method :_orig_create, :create
286
+ alias_method :_orig_create, :create
305
287
 
306
- def create(*)
307
- model = super
308
- model.save
309
- model
310
- end
288
+ def create(*)
289
+ model = super
290
+ model.save
291
+ model
292
+ end
311
293
 
312
- def create!(*args)
313
- model = _orig_create(*args)
314
- model.save!
315
- model
316
- end
294
+ def create!(*args)
295
+ model = _orig_create(*args)
296
+ model.save!
297
+ model
298
+ end
317
299
 
318
- tx_methods :create, :create!
300
+ tx_methods :create, :create!
319
301
 
320
302
 
321
- def transaction(&block)
322
- Neo4j::Rails::Transaction.run &block
323
- end
303
+ def transaction(&block)
304
+ Neo4j::Rails::Transaction.run &block
305
+ end
324
306
 
325
- def accepts_nested_attributes_for(*attr_names)
326
- options = attr_names.pop if attr_names[-1].is_a?(Hash)
307
+ def accepts_nested_attributes_for(*attr_names)
308
+ options = attr_names.pop if attr_names[-1].is_a?(Hash)
327
309
 
328
- attr_names.each do |association_name|
329
- rel = self._decl_rels[association_name.to_sym]
330
- raise "No relationship declared with has_n or has_one with type #{association_name}" unless rel
331
- to_class = rel.to_class
332
- raise "Can't use accepts_nested_attributes_for(#{association_name}) since it has not defined which class it has a relationship to, use has_n(#{association_name}).to(MyOtherClass)" unless to_class
333
- type = rel.namespace_type
334
- has_one = rel.has_one?
310
+ attr_names.each do |association_name|
311
+ rel = self._decl_rels[association_name.to_sym]
312
+ raise "No relationship declared with has_n or has_one with type #{association_name}" unless rel
313
+ to_class = rel.to_class
314
+ raise "Can't use accepts_nested_attributes_for(#{association_name}) since it has not defined which class it has a relationship to, use has_n(#{association_name}).to(MyOtherClass)" unless to_class
315
+ type = rel.namespace_type
316
+ has_one = rel.has_one?
335
317
 
336
- send(:define_method, "#{association_name}_attributes=") do |attributes|
337
- if has_one
338
- update_nested_attributes(type, to_class, true, attributes, options)
339
- else
340
- if attributes.is_a?(Array)
341
- attributes.each do |attr|
342
- update_nested_attributes(type, to_class, false, attr, options)
343
- end
344
- else
345
- attributes.each_value do |attr|
346
- update_nested_attributes(type, to_class, false, attr, options)
318
+ send(:define_method, "#{association_name}_attributes=") do |attributes|
319
+ if has_one
320
+ update_nested_attributes(type, to_class, true, attributes, options)
321
+ else
322
+ if attributes.is_a?(Array)
323
+ attributes.each do |attr|
324
+ update_nested_attributes(type, to_class, false, attr, options)
325
+ end
326
+ else
327
+ attributes.each_value do |attr|
328
+ update_nested_attributes(type, to_class, false, attr, options)
329
+ end
330
+ end
347
331
  end
348
332
  end
333
+ tx_methods("#{association_name}_attributes=")
349
334
  end
350
335
  end
351
- tx_methods("#{association_name}_attributes=")
336
+
352
337
  end
338
+
353
339
  end
354
340
 
355
341
  end
356
-
357
342
  end
358
343
 
@@ -1,11 +1,15 @@
1
- module Neo4j::TxMethods
2
- def tx_methods(*methods)
3
- methods.each do |method|
4
- tx_method = "#{method}_in_tx"
5
- send(:alias_method, tx_method, method)
6
- send(:define_method, method) do |*args|
7
- Neo4j::Rails::Transaction.running? ? send(tx_method, *args) : Neo4j::Rails::Transaction.run { send(tx_method, *args) }
1
+ module Neo4j
2
+ module Rails
3
+ module TxMethods
4
+ def tx_methods(*methods)
5
+ methods.each do |method|
6
+ tx_method = "#{method}_in_tx"
7
+ send(:alias_method, tx_method, method)
8
+ send(:define_method, method) do |*args|
9
+ Neo4j::Rails::Transaction.running? ? send(tx_method, *args) : Neo4j::Rails::Transaction.run { send(tx_method, *args) }
10
+ end
11
+ end
8
12
  end
9
13
  end
10
14
  end
11
- end
15
+ end
@@ -1,16 +1,13 @@
1
- module Neo4j
1
+ module Neo4j::Rails
2
2
 
3
3
  class Value
4
4
  include Neo4j::Property
5
5
  include org.neo4j.graphdb.Node
6
6
 
7
- def initialize(*args)
8
- # the first argument can be an hash of properties to set
7
+ def initialize(wrapper)
8
+ @wrapper = wrapper
9
9
  @props = {}
10
- if args[0].respond_to?(:each_pair)
11
- args[0].each_pair { |k, v| set_property(k.to_s, v) }
12
- end
13
- @rels = {} # a hash of all relationship with key type
10
+ @outgoing_rels = {} # a hash of all relationship with key type
14
11
  end
15
12
 
16
13
  # override Neo4j::Property#props
@@ -22,6 +19,23 @@ module Neo4j
22
19
  nil
23
20
  end
24
21
 
22
+
23
+ def create_relationship_to(other_java_node, java_type)
24
+ outgoing(java_type.name).new(other_java_node)
25
+ end
26
+
27
+ def getSingleRelationship(type, dir)
28
+ # TODO incoming not implemented, needed ?
29
+ @outgoing_rels[type.name] && @outgoing_rels[type.name].rels.first
30
+ end
31
+
32
+ def getRelationships(*args)
33
+ type = args[0].name
34
+ outgoing = @outgoing_rels[type]
35
+ return [] unless outgoing
36
+ outgoing.rels
37
+ end
38
+
25
39
  # Pretend this object is a Java Node
26
40
  def has_property?(key)
27
41
  !@props[key].nil?
@@ -39,16 +53,22 @@ module Neo4j
39
53
  @props.delete(key)
40
54
  end
41
55
 
56
+ def wrapper
57
+ @wrapper
58
+ end
59
+
42
60
  def outgoing(type)
43
- @rels[type.to_sym] ||= OutgoingRels.new
61
+ @outgoing_rels[type.to_s] ||= OutgoingRels.new(self)
44
62
  end
45
63
 
46
64
  def save_nested(root_node)
47
65
  valid = true
48
- @rels.each_pair do |type, rel|
66
+ @outgoing_rels.each_pair do |type, rel|
49
67
  rel.each do |new_node|
50
- if new_node.save
51
- root_node.outgoing(type) << new_node
68
+ wrapper = new_node.respond_to?(:wrapper) ? new_node.wrapper : new_node
69
+ if wrapper.save
70
+ puts "NEW RELATIONSHIP OF TYPE #{type} from #{root_node} to #{new_node}"
71
+ root_node.outgoing(type) << wrapper
52
72
  else
53
73
  valid = false
54
74
  end
@@ -57,22 +77,55 @@ module Neo4j
57
77
  valid
58
78
  end
59
79
 
80
+ class Relationship
81
+ include org.neo4j.graphdb.Relationship
82
+ attr_reader :end_node, :start_node
83
+
84
+ def initialize(from, to)
85
+ @end_node = to
86
+ @start_node = from
87
+ end
88
+
89
+ def wrapper
90
+ self
91
+ end
92
+
93
+ def getOtherNode(other)
94
+ other == @end_node ? @start_node : @end_node
95
+ end
96
+ end
97
+
98
+
60
99
  class OutgoingRels
61
100
  include Enumerable
62
- def initialize
63
- @nodes = []
101
+ attr_reader :rels
102
+
103
+ def initialize(start_node)
104
+ @rels = []
105
+ @start_node = start_node
64
106
  end
65
107
 
66
108
  def <<(other)
67
- @nodes << other
109
+ new(other)
110
+ self
111
+ end
112
+
113
+ def new(other)
114
+ new_rel = Relationship.new(@start_node, other)
115
+ @rels << new_rel
116
+ new_rel
68
117
  end
69
118
 
70
119
  def each
71
- @nodes.each {|n| yield n}
120
+ @rels.each {|n| yield n.end_node}
121
+ end
122
+
123
+ def clear
124
+ @rels.clear
72
125
  end
73
126
 
74
127
  def empty?
75
- @nodes.empty?
128
+ @rels.empty?
76
129
  end
77
130
 
78
131
  def is_a?(type)
@@ -16,10 +16,7 @@ module Neo4j
16
16
  end
17
17
 
18
18
  def each
19
- iter = iterator
20
- while (iter.hasNext) do
21
- yield iter.next.wrapper
22
- end
19
+ iterator.each {|i| yield i.wrapper}
23
20
  end
24
21
 
25
22
  def iterator
data/lib/neo4j/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Neo4j
2
- VERSION = "1.0.0.beta.11"
2
+ VERSION = "1.0.0.beta.12"
3
3
  end
metadata CHANGED
@@ -7,8 +7,8 @@ version: !ruby/object:Gem::Version
7
7
  - 0
8
8
  - 0
9
9
  - beta
10
- - 11
11
- version: 1.0.0.beta.11
10
+ - 12
11
+ version: 1.0.0.beta.12
12
12
  platform: ruby
13
13
  authors:
14
14
  - Andreas Ronge
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-10-08 00:00:00 +02:00
19
+ date: 2010-10-12 00:00:00 +02:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -102,6 +102,7 @@ extra_rdoc_files:
102
102
  files:
103
103
  - lib/neo4j.rb
104
104
  - lib/neo4j/event_handler.rb
105
+ - lib/neo4j/model.rb
105
106
  - lib/neo4j/node_traverser.rb
106
107
  - lib/neo4j/relationship_traverser.rb
107
108
  - lib/neo4j/config.rb