neo4j 2.0.0.alpha.5-java → 2.0.0.alpha.6-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/CHANGELOG +12 -0
  2. data/Gemfile +0 -4
  3. data/README.rdoc +106 -62
  4. data/lib/neo4j.rb +7 -33
  5. data/lib/neo4j/performance.rb +43 -0
  6. data/lib/neo4j/rails/accept_id.rb +19 -18
  7. data/lib/neo4j/rails/attributes.rb +366 -120
  8. data/lib/neo4j/rails/finders.rb +41 -15
  9. data/lib/neo4j/rails/has_n.rb +203 -0
  10. data/lib/neo4j/rails/identity.rb +25 -0
  11. data/lib/neo4j/rails/model.rb +65 -242
  12. data/lib/neo4j/rails/nested_attributes.rb +108 -0
  13. data/lib/neo4j/rails/node_persistance.rb +56 -0
  14. data/lib/neo4j/rails/observer.rb +0 -2
  15. data/lib/neo4j/rails/persistence.rb +32 -154
  16. data/lib/neo4j/rails/rack_middleware.rb +26 -2
  17. data/lib/neo4j/rails/rails.rb +9 -6
  18. data/lib/neo4j/rails/railtie.rb +1 -2
  19. data/lib/neo4j/rails/relationship.rb +18 -125
  20. data/lib/neo4j/rails/relationship_persistence.rb +107 -0
  21. data/lib/neo4j/rails/relationships/node_dsl.rb +72 -44
  22. data/lib/neo4j/rails/relationships/relationships.rb +187 -59
  23. data/lib/neo4j/rails/relationships/rels_dsl.rb +18 -17
  24. data/lib/neo4j/rails/relationships/storage.rb +19 -17
  25. data/lib/neo4j/rails/timestamps.rb +53 -51
  26. data/lib/neo4j/rails/transaction.rb +9 -1
  27. data/lib/neo4j/rails/validations/uniqueness.rb +1 -1
  28. data/lib/neo4j/rails/versioning/versioning.rb +2 -2
  29. data/lib/neo4j/version.rb +1 -1
  30. data/lib/orm_adapter/adapters/neo4j.rb +47 -46
  31. data/neo4j.gemspec +1 -1
  32. metadata +10 -69
  33. data/lib/neo4j/algo/algo.rb +0 -294
  34. data/lib/neo4j/batch/batch.rb +0 -4
  35. data/lib/neo4j/batch/indexer.rb +0 -109
  36. data/lib/neo4j/batch/inserter.rb +0 -179
  37. data/lib/neo4j/batch/rule_inserter.rb +0 -24
  38. data/lib/neo4j/batch/rule_node.rb +0 -72
  39. data/lib/neo4j/config.rb +0 -177
  40. data/lib/neo4j/core_ext/class/inheritable_attributes.rb +0 -12
  41. data/lib/neo4j/core_ext/class/rewrite_inheritable_attributes.rb +0 -170
  42. data/lib/neo4j/database.rb +0 -158
  43. data/lib/neo4j/equal.rb +0 -21
  44. data/lib/neo4j/event_handler.rb +0 -263
  45. data/lib/neo4j/has_list/class_methods.rb +0 -11
  46. data/lib/neo4j/has_list/has_list.rb +0 -3
  47. data/lib/neo4j/has_list/mapping.rb +0 -133
  48. data/lib/neo4j/has_n/class_methods.rb +0 -119
  49. data/lib/neo4j/has_n/decl_relationship_dsl.rb +0 -246
  50. data/lib/neo4j/has_n/has_n.rb +0 -3
  51. data/lib/neo4j/has_n/mapping.rb +0 -98
  52. data/lib/neo4j/identity_map.rb +0 -140
  53. data/lib/neo4j/index/class_methods.rb +0 -108
  54. data/lib/neo4j/index/index.rb +0 -39
  55. data/lib/neo4j/index/indexer.rb +0 -341
  56. data/lib/neo4j/index/indexer_registry.rb +0 -68
  57. data/lib/neo4j/index/lucene_query.rb +0 -256
  58. data/lib/neo4j/load.rb +0 -25
  59. data/lib/neo4j/migrations/class_methods.rb +0 -110
  60. data/lib/neo4j/migrations/extensions.rb +0 -58
  61. data/lib/neo4j/migrations/lazy_node_mixin.rb +0 -41
  62. data/lib/neo4j/migrations/migration.rb +0 -112
  63. data/lib/neo4j/migrations/migrations.rb +0 -6
  64. data/lib/neo4j/migrations/node_mixin.rb +0 -80
  65. data/lib/neo4j/migrations/ref_node_wrapper.rb +0 -32
  66. data/lib/neo4j/model.rb +0 -4
  67. data/lib/neo4j/neo4j.rb +0 -216
  68. data/lib/neo4j/node.rb +0 -270
  69. data/lib/neo4j/node_mixin/class_methods.rb +0 -51
  70. data/lib/neo4j/node_mixin/node_mixin.rb +0 -141
  71. data/lib/neo4j/paginated.rb +0 -23
  72. data/lib/neo4j/property/class_methods.rb +0 -79
  73. data/lib/neo4j/property/property.rb +0 -111
  74. data/lib/neo4j/rails/mapping/property.rb +0 -183
  75. data/lib/neo4j/rails/rel_persistence.rb +0 -237
  76. data/lib/neo4j/relationship.rb +0 -239
  77. data/lib/neo4j/relationship_mixin/class_methods.rb +0 -36
  78. data/lib/neo4j/relationship_mixin/relationship_mixin.rb +0 -142
  79. data/lib/neo4j/relationship_set.rb +0 -58
  80. data/lib/neo4j/rels/rels.rb +0 -110
  81. data/lib/neo4j/rels/traverser.rb +0 -102
  82. data/lib/neo4j/rule/class_methods.rb +0 -201
  83. data/lib/neo4j/rule/event_listener.rb +0 -66
  84. data/lib/neo4j/rule/functions/count.rb +0 -43
  85. data/lib/neo4j/rule/functions/function.rb +0 -74
  86. data/lib/neo4j/rule/functions/functions.rb +0 -3
  87. data/lib/neo4j/rule/functions/sum.rb +0 -29
  88. data/lib/neo4j/rule/rule.rb +0 -150
  89. data/lib/neo4j/rule/rule_node.rb +0 -217
  90. data/lib/neo4j/to_java.rb +0 -31
  91. data/lib/neo4j/transaction.rb +0 -73
  92. data/lib/neo4j/traversal/filter_predicate.rb +0 -25
  93. data/lib/neo4j/traversal/prune_evaluator.rb +0 -14
  94. data/lib/neo4j/traversal/rel_expander.rb +0 -31
  95. data/lib/neo4j/traversal/traversal.rb +0 -141
  96. data/lib/neo4j/traversal/traverser.rb +0 -284
  97. data/lib/neo4j/type_converters/type_converters.rb +0 -288
@@ -6,11 +6,26 @@ module Neo4j
6
6
  module Finders
7
7
  extend ActiveSupport::Concern
8
8
 
9
+
10
+ def reachable_from_ref_node?
11
+ # All relationships are reachable
12
+ respond_to?(:_java_rel) || Neo4j::Algo.all_path(self.class.ref_node_for_class, self).outgoing(self.class).outgoing(:_all).first != nil
13
+ end
14
+
9
15
  included do
10
- rule(:_all, :functions => Neo4j::Rule::Functions::Count.new)
16
+ rule(:_all, :functions => Neo4j::Wrapper::Rule::Functions::Size.new) if respond_to?(:rule)
11
17
  end
12
18
 
13
19
  module ClassMethods
20
+
21
+ def index_prefix
22
+ return "" unless Neo4j.running?
23
+ return "" unless respond_to?(:ref_node_for_class)
24
+ ref_node = ref_node_for_class.wrapper
25
+ prefix = ref_node.respond_to?(:index_prefix) ? ref_node.send(:index_prefix) : ref_node[:name]
26
+ prefix ? prefix + "_" : ""
27
+ end
28
+
14
29
  # overwrite the index method to add find_by_xxx class methods
15
30
  def index(*args)
16
31
  field = args.first
@@ -40,7 +55,7 @@ module Neo4j
40
55
 
41
56
  # load an id or array of ids from the database
42
57
  def load(*ids)
43
- result = ids.map { |id| entity_load(id) }
58
+ result = ids.map { |id| load_entity(id) }
44
59
  if ids.length == 1
45
60
  result.first
46
61
  else
@@ -48,6 +63,8 @@ module Neo4j
48
63
  end
49
64
  end
50
65
 
66
+ Neo4j::Wrapper::Find.send(:alias_method, :_wrapper_find, :find)
67
+
51
68
  # Behave like the ActiveRecord query interface
52
69
  #
53
70
  # === Example
@@ -68,18 +85,18 @@ module Neo4j
68
85
  # Model.find(:all, :conditions => "name: test")
69
86
  # Model.find(:all, :conditions => { :name => "test" })
70
87
  #
71
- def find(*args)
88
+ def find(*args, &block)
72
89
  case args.first
73
90
  when :all, :first
74
91
  kind = args.shift
75
- send(kind, *args)
92
+ send(kind, *args, &block)
76
93
  when "0", 0, nil
77
94
  nil
78
95
  else
79
96
  if convertable_to_id?(args.first)
80
97
  find_with_ids(*args)
81
98
  else
82
- first(*args)
99
+ first(*args, &block)
83
100
  end
84
101
  end
85
102
  end
@@ -124,7 +141,7 @@ module Neo4j
124
141
  find_or(:new, attrs, &block)
125
142
  end
126
143
 
127
- def all(*args)
144
+ def all(*args, &block)
128
145
  if !conditions_in?(*args)
129
146
  # use the _all rule to recover all the stored instances of this node
130
147
  _all
@@ -134,18 +151,18 @@ module Neo4j
134
151
  if ids
135
152
  [find_with_ids(ids)].flatten
136
153
  else
137
- find_with_indexer(*args)
154
+ find_with_indexer(*args, &block)
138
155
  end
139
156
  end
140
157
  end
141
158
 
142
- def first(*args)
143
- all(*args).first
159
+ def first(*args, &block)
160
+ all(*args, &block).first
144
161
  end
145
162
 
146
163
  def last(*args)
147
164
  a = all(*args)
148
- a.empty? ? nil : a[a.size - 1]
165
+ a.empty? ? nil : a[all.size - 1]
149
166
  end
150
167
 
151
168
  def count
@@ -201,14 +218,23 @@ module Neo4j
201
218
  end
202
219
 
203
220
  def findable?(entity)
204
- entity.is_a? self
221
+ entity.is_a?(self) and entity.reachable_from_ref_node?
205
222
  end
206
223
 
207
- def find_with_indexer(*args)
208
- hits = _indexer.find(*args)
224
+ def find_with_indexer(*args, &block)
225
+ hits = if args.first.is_a?(Hash) && args.first.include?(:conditions)
226
+ params = args.first.clone
227
+ params.delete(:conditions)
228
+ raise "ARGS #{args.inspect}" if args.size > 1
229
+ _wrapper_find(args.first[:conditions], params, &block)
230
+ else
231
+ _wrapper_find(*args, &block)
232
+ end
233
+
234
+
209
235
  # We need to save this so that the Rack Neo4j::Rails:LuceneConnection::Closer can close it
210
236
  Thread.current[:neo4j_lucene_connection] ||= []
211
- Thread.current[:neo4j_lucene_connection] << hits
237
+ Thread.current[:neo4j_lucene_connection] << hits if hits.respond_to?(:close)
212
238
  hits
213
239
  end
214
240
 
@@ -222,7 +248,7 @@ module Neo4j
222
248
  #
223
249
  # @return [ Node ] The first or new node.
224
250
  def find_or(method, attrs = {}, &block)
225
- first(:conditions => attrs) || send(method, attrs, &block)
251
+ first(attrs) || send(method, attrs, &block)
226
252
  end
227
253
  end
228
254
  end
@@ -0,0 +1,203 @@
1
+ module Neo4j
2
+ module Rails
3
+ module HasN
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+
8
+ # Create a number of methods similar to active record has_many.
9
+ # The first one returns an Neo4j::Rails::Relationships::NodesDSL
10
+ # the second generate method (with the _rels postfix) returns a
11
+ # Neo4j::Rails::Relationships::RelsDSL
12
+ #
13
+ # See also Neo4j::NodeMixin#has_n which only work with persisted relationships.
14
+ #
15
+ # @example
16
+ # class Thing
17
+ # has_n(:things)
18
+ # end
19
+ #
20
+ # t = Thing.new
21
+ # t.things << Thing.new << OtherClass.new
22
+ # t.save # saves all nodes and relationships
23
+ #
24
+ # @example declare a to relationship
25
+ # class Company
26
+ # has_n(:employees).to(Person)
27
+ # end
28
+ #
29
+ # c = Company.new
30
+ # c.employees << Person.new << Person.new(:name => 'kalle')
31
+ #
32
+ # @example creates a new person and relationship
33
+ # c.employees.build(:name => 'sune')
34
+ #
35
+ # @example creates a new person and relationship and persist it
36
+ # c.employees.create(:name => 'sune')
37
+ #
38
+ # @example delete all nodes and relationships
39
+ # c.employees.destroy_all
40
+ #
41
+ # @example access the relationships and destroy them
42
+ # c.employees_rels.destroy_all
43
+ #
44
+ # @example advanced traversal, using Neo4j::Core::Traversal
45
+ # c._outgoing(Company.employees).outgoing(:friends).depth.each{ }
46
+ #
47
+ # @see Neo4j::Rails::Relationships::NodesDSL
48
+ def has_n(*args)
49
+ options = args.extract_options!
50
+ define_has_n_methods_for(args.first, options)
51
+ end
52
+
53
+ # Declares ONE incoming or outgoing relationship
54
+ #
55
+ # @example
56
+ # class Person
57
+ # has_one(:friend).to(OtherClass)
58
+ # end
59
+ #
60
+ # @example
61
+ # person.best_friend = my_friend
62
+ #
63
+ # @example
64
+ # person.best_friend # => my_friend
65
+ #
66
+ # @example
67
+ # person.build_best_friend(:name => 'foo')
68
+ #
69
+ # @example
70
+ # person.create_best_friend(:name => 'foo')
71
+ #
72
+ # @example
73
+ # person.create_best_friend!(:name => 'foo')
74
+ #
75
+ # @notice when using the <tt>build_</tt> and <tt>create_</tt> methods you <b>must</b> specify a <tt>to</to> relationship as done above in the Person example
76
+ def has_one(*args)
77
+ options = args.extract_options!
78
+ define_has_one_methods_for(args.first, options)
79
+ end
80
+
81
+ protected
82
+
83
+ def define_has_one_methods_for(rel_type, options)
84
+ unless method_defined?(rel_type)
85
+ class_eval <<-RUBY, __FILE__, __LINE__
86
+ def #{rel_type}
87
+ dsl = _decl_rels_for(:'#{rel_type}')
88
+ storage = _create_or_get_storage_for_decl_rels(dsl)
89
+ storage.single_node(dsl.dir)
90
+ end
91
+ RUBY
92
+ end
93
+
94
+ unless method_defined?("#{rel_type}_rel")
95
+ class_eval <<-RUBY, __FILE__, __LINE__
96
+ def #{rel_type}_rel
97
+ dsl = _decl_rels_for(:'#{rel_type}')
98
+ storage = _create_or_get_storage_for_decl_rels(dsl)
99
+ storage.single_relationship(dsl.dir)
100
+ end
101
+ RUBY
102
+ end
103
+
104
+ unless method_defined?("#{rel_type}=".to_sym)
105
+ class_eval <<-RUBY, __FILE__, __LINE__
106
+ def #{rel_type}=(other)
107
+ dsl = _decl_rels_for(:'#{rel_type}')
108
+ storage = _create_or_get_storage_for_decl_rels(dsl)
109
+ storage.destroy_single_relationship(dsl.dir)
110
+ storage.create_relationship_to(other, dsl.dir) if other
111
+ end
112
+ RUBY
113
+ end
114
+
115
+ unless method_defined?("build_#{rel_type}".to_sym)
116
+ class_eval <<-RUBY, __FILE__, __LINE__
117
+ def build_#{rel_type}(attr)
118
+ dsl = _decl_rels_for(:'#{rel_type}')
119
+ storage = _create_or_get_storage_for_decl_rels(dsl)
120
+ NodesDSL.new(storage, dsl.dir).build(attr)
121
+ end
122
+ RUBY
123
+ end
124
+
125
+ unless method_defined?("create_#{rel_type}".to_sym)
126
+ class_eval <<-RUBY, __FILE__, __LINE__
127
+ def create_#{rel_type}(attr)
128
+ dsl = _decl_rels_for(:'#{rel_type}')
129
+ storage = _create_or_get_storage_for_decl_rels(dsl)
130
+ NodesDSL.new(storage, dsl.dir).create(attr)
131
+ end
132
+ RUBY
133
+ end
134
+
135
+ unless method_defined?("create_#{rel_type}!".to_sym)
136
+ class_eval <<-RUBY, __FILE__, __LINE__
137
+ def create_#{rel_type}!(attr)
138
+ dsl = _decl_rels_for(:'#{rel_type}')
139
+ storage = _create_or_get_storage_for_decl_rels(dsl)
140
+ NodesDSL.new(storage, dsl.dir).create!(attr)
141
+ end
142
+ RUBY
143
+ end
144
+
145
+ _decl_rels[rel_type.to_sym] = Neo4j::Wrapper::HasN::DeclRel.new(rel_type, true, self)
146
+ end
147
+
148
+ def define_has_n_methods_for(rel_type, options) #:nodoc:
149
+ unless method_defined?(rel_type)
150
+ class_eval <<-RUBY, __FILE__, __LINE__
151
+ def #{rel_type}
152
+ dsl = _decl_rels_for(:'#{rel_type}')
153
+ storage = _create_or_get_storage_for_decl_rels(dsl)
154
+ NodesDSL.new(storage, dsl.dir)
155
+ end
156
+ RUBY
157
+ end
158
+
159
+ unless method_defined?("#{rel_type}=".to_sym)
160
+
161
+ # TODO: This is a temporary fix for allowing running neo4j with Formtastic, issue 109
162
+ # A better solution might be to implement accept_ids for has_n relationship and
163
+ # make sure (somehow) that Formtastic uses the _ids methods.
164
+
165
+ class_eval <<-RUBY, __FILE__, __LINE__
166
+ def #{rel_type}=(nodes)
167
+ if nodes.is_a?(Array) && nodes.first.is_a?(String)
168
+ if nodes.first.blank?
169
+ self.#{rel_type}_rels.destroy_all
170
+ nodes.shift
171
+ end
172
+ else
173
+ self.#{rel_type}_rels.destroy_all
174
+ end
175
+ association = self.#{rel_type}
176
+ nodes.each { |node| association << node }
177
+ end
178
+ RUBY
179
+ end
180
+
181
+ unless method_defined?("#{rel_type}_rels".to_sym)
182
+ class_eval <<-RUBY, __FILE__, __LINE__
183
+ def #{rel_type}_rels
184
+ dsl = _decl_rels_for(:'#{rel_type}')
185
+ storage = _create_or_get_storage_for_decl_rels(dsl)
186
+ RelsDSL.new(storage, dsl.dir)
187
+ end
188
+ RUBY
189
+ end
190
+
191
+ instance_eval <<-RUBY, __FILE__, __LINE__
192
+ def #{rel_type}
193
+ _decl_rels[:'#{rel_type}'].rel_type.to_s
194
+ end
195
+ RUBY
196
+
197
+ _decl_rels[rel_type.to_sym] = Neo4j::Wrapper::HasN::DeclRel.new(rel_type, false, self)
198
+ end
199
+
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,25 @@
1
+ module Neo4j
2
+ module Rails
3
+ module Identity
4
+
5
+ def id
6
+ _java_entity ? _java_entity.neo_id.to_s : nil
7
+ end
8
+
9
+ def neo_id
10
+ _java_entity ? _java_entity.neo_id : nil
11
+ end
12
+
13
+ def getId
14
+ new_record? ? nil : neo_id
15
+ end
16
+
17
+ def ==(other)
18
+ new? ? self.__id__ == other.__id__ : _java_entity == (other)
19
+ end
20
+
21
+
22
+ end
23
+ end
24
+ end
25
+
@@ -1,285 +1,108 @@
1
1
  module Neo4j
2
2
  module Rails
3
-
4
- # Includes the Neo4j::NodeMixin and adds ActiveRecord/Model like behaviour.
3
+ # Makes Neo4j nodes and relationships behave like active record objects.
5
4
  # That means for example that you don't have to care about transactions since they will be
6
- # automatically be created when needed.
5
+ # automatically be created when needed. Validation, Callbacks etc. are also supported.
7
6
  #
8
- # ==== Included Mixins
7
+ # @example Traverse
8
+ # class Person < Neo4j::Rails::Model
9
+ # end
9
10
  #
10
- # * Neo4j::Rails::Persistence :: handles how to save, create and update the model
11
- # * Neo4j::Rails::Attributes :: handles how to save and retrieve attributes
12
- # * Neo4j::Rails::Mapping::Property :: allows some additional options on the #property class method
13
- # * Neo4j::Rails::Serialization :: enable to_xml and to_json
14
- # * Neo4j::Rails::Timestamps :: handle created_at, updated_at timestamp properties
15
- # * Neo4j::Rails::Validations :: enable validations
16
- # * Neo4j::Rails::Callbacks :: enable callbacks
17
- # * Neo4j::Rails::Finders :: ActiveRecord style find
18
- # * Neo4j::Rails::Relationships :: handles persisted and none persisted relationships.
19
- # * Neo4j::Rails::Compositions :: see Neo4j::Rails::Compositions::ClassMethods, similar to http://api.rubyonrails.org/classes/ActiveRecord/Aggregations/ClassMethods.html
20
- # * ActiveModel::Observing # enable observers, see Rails documentation.
21
- # * ActiveModel::Translation - class mixin
11
+ # person = Person.find(...)
12
+ # person.outgoing(:foo) << Person.create
13
+ # person.save!
14
+ # person.outgoing(:foo).depth(:all)...
15
+ # person.outgoing(:friends).map{|f| f.outgoing(:knows).to_a}.flatten
22
16
  #
23
- # ==== Traversals
24
- # This class only expose a limited set of traversals.
25
- # If you want to access the raw java node to do traversals use the _java_node.
17
+ # @example Declared Relationships: has_n and has_one
26
18
  #
27
19
  # class Person < Neo4j::Rails::Model
28
20
  # end
29
21
  #
30
- # person = Person.find(...)
31
- # person._java_node.outgoing(:foo).depth(:all)...
22
+ # class Person
23
+ # has_n(:friends).to(Person)
24
+ # has_n(:employed_by)
25
+ # end
26
+ #
27
+ # Person.new.foo << other_node
28
+ # Person.friends.build(:name => 'kalle')
32
29
  #
33
- # ==== has_n and has_one
30
+ # @example Declared Properties and Index
34
31
  #
35
- # The has_n and has_one relationship accessors returns objects of type Neo4j::Rails::Relationships::RelsDSL
36
- # and Neo4j::Rails::Relationships::NodesDSL which behaves more like the Active Record relationships.
37
- # Notice that unlike Neo4j::NodeMixin new relationships are kept in memory until @save@ is called.
32
+ # class Person < Neo4j::Rails::Model
33
+ # property :name
34
+ # property :age, :type => Fixnum, :index => :exact
35
+ # end
38
36
  #
39
- # ==== Callbacks
37
+ # Person.create(:name => 'kalle', :age => 42, :undeclared_prop => 3.14)
38
+ # Person.find_by_age(42)
40
39
  #
41
- # The following callbacks are supported :validation, :create, :destroy, :save, :update.
42
- # It works with before, after and around callbacks, see the Rails documentation.
43
- # Notice you can also do callbacks using the Neo4j::Rails::Callbacks module (check the Rails documentation)
40
+ # @example Callbacks
41
+ #
42
+ # class Person < Neo4j::Rails::Model
43
+ # before_save :do_something
44
+ # def do_something
45
+ # end
46
+ # end
47
+ #
48
+ # = Class Method Modules
49
+ # * {Neo4j::Rails::Persistence::ClassMethods} defines methods like: <tt>create</tt> and <tt>destroy_all</tt>
50
+ # * {Neo4j::Rails::Attributes::ClassMethods} defines the <tt>property</tt> and <tt>columns</tt> methods.
51
+ # * {Neo4j::Rails::NestedAttributes::ClassMethods} defines <tt>accepts_nested_attributes_for</tt>
52
+ # * {Neo4j::Rails::HasN::ClassMethods} defines <tt>has_n</tt> and <tt>has_one</tt>
53
+ # * {Neo4j::Rails::Finders::ClassMethods} defines <tt>find</tt>
54
+ # * {Neo4j::Rails::Compositions::ClassMethods} defines <tt>composed_of</tt> method
55
+ # * {Neo4j::Rails::AcceptId::ClassMethods} defines <tt>accepts_id_for</tt> method.
44
56
  #
45
57
  class Model
46
- include Neo4j::NodeMixin
47
-
48
-
49
- # Initialize a Node with a set of properties (or empty if nothing is passed)
50
- def initialize(attributes = {})
51
- @properties_before_type_cast=java.util.HashMap.new
52
- reset_attributes
53
- clear_relationships
54
- self.attributes = attributes if attributes.is_a?(Hash)
55
- yield self if block_given?
56
- end
57
-
58
- def id
59
- neo_id.nil? ? nil : neo_id.to_s
60
- end
61
-
62
- def hash
63
- persisted? ? _java_entity.neo_id.hash : super
64
- end
65
-
66
- def to_param
67
- persisted? ? neo_id.to_s : nil
68
- end
69
-
70
-
71
- # Returns an Enumerable of all (primary) key attributes
72
- # or nil if model.persisted? is false
73
- def to_key
74
- persisted? ? [id] : nil
75
- end
76
-
77
- def reject_if?(proc_or_symbol, attr)
78
- return false if proc_or_symbol.nil?
79
- if proc_or_symbol.is_a?(Symbol)
80
- meth = method(proc_or_symbol)
81
- meth.arity == 0 ? meth.call : meth.call(attr)
82
- else
83
- proc_or_symbol.call(attr)
84
- end
85
- end
86
-
87
- def to_model
88
- self
89
- end
90
-
91
- def ==(other)
92
- new? ? self.__id__ == other.__id__ : @_java_node == (other)
93
- end
94
-
95
- def reachable_from_ref_node?
96
- Neo4j::Algo.all_path(self.class.ref_node_for_class, self).outgoing(self.class).outgoing(:_all).count > 0
97
- end
98
-
99
- def attribute_missing(method_id, *args, &block)
100
- method_name = method_id.method_name
101
- if property?(method_name)
102
- self[method_name]
103
- else
104
- super
105
- end
106
- end
107
-
108
- ##
109
- # :method: outgoing
110
- #
111
- # Similar to Neo4j::Traversal#outgoing but returns depth one only outgoing relationship
112
- # which may not all be persisted.
113
- # For only traversing persisted outgoing relationship of any depth or more advanced traversals, use
114
- # the wrapped Java node instead.
115
- #
116
- # ==== Examples
117
- #
118
- # person.outgoing(:friends) << other_person
119
- # person.save!
120
- #
121
- # person.outgoing(:friends).map{|f| f.outgoing(:knows).to_a}.flatten
122
- #
123
- # ==== Examples
124
- #
125
- # Neo4j::Transaction.run do
126
- # person._java_node.outgoing(:friends) << other_person
127
- # end
128
- #
129
- # person._java_node.outgoing(:friends).outgoing(:knows).depth(4)
130
- #
131
- # Notice you can also declare outgoing relationships with the #has_n and #has_one class method.
132
- #
133
- # See Neo4j::Rails::Relationships#outgoing
134
- # See Neo4j::Traversal#outgoing (when using it from the _java_node)
135
-
136
-
137
- ##
138
- # :method: incoming
139
- #
140
- # Returns incoming relationship of depth one which may not all be persisted.
141
- # See #outgoing
142
-
143
-
144
- ##
145
- # :method: rels
146
- #
147
- # Returns both incoming and outgoing relationships which may not all be persisted.
148
- # If you only want to find persisted relationships: @node._java_node.rels@
149
- #
150
- # See Neo4j::Rails::Relationships#rels
151
- # See Neo4j::Rels#rels or Neo4j::Rels
152
- #
153
-
154
- ##
155
- # :method: []
156
- #
157
- # Returns a property of this node, which may or may not have been declared with the class property method.
158
- # Similar to Neo4j::Property#[] but can return not persisted properties as well.
159
-
160
- ##
161
- # :method: []=
162
- #
163
- # Sets any property on the node.
164
- # Similar to Neo4j::Property#[]= but you must call the #save method to persist the property.
165
-
166
- ##
167
- # :singleton-method: property
168
- #
169
- # See Neo4j::Rails::Mapping::Property::ClassMethods#property
170
-
171
- ##
172
- # :singleton-method: has_one
173
- #
174
- # Generates a has_one methods which returns an object of type Neo4j::Rails::Relationships::NodesDSL
175
- # and a has_one method postfixed @_rel@ which return a Neo4j::Rails::Relationships::RelsDSL
176
- #
177
- # See also Neo4j::Rails::Mapping::Property::ClassMethods#has_one
178
- #
179
-
180
- ##
181
- # :singleton-method: columns
182
- #
183
- # Returns all defined properties as an array
184
-
185
- ##
186
- # :singleton-method: has_n
187
- #
188
- # Generates a has_n method which returns an object of type Neo4j::Rails::Relationships::NodesDSL
189
- # and a has_n method postfixed @_rel@ which return a Neo4j::Rails::Relationships::RelsDSL
190
- #
191
- # See also Neo4j::Rails::Mapping::Property::ClassMethods#has_n
192
- #
58
+ extend ActiveModel::Translation
193
59
 
60
+ include Neo4j::NodeMixin
61
+ include ActiveModel::Dirty # track changes to attributes
62
+ include ActiveModel::MassAssignmentSecurity # handle attribute hash assignment
63
+ include ActiveModel::Observing # enable observers
64
+ include Neo4j::Rails::Identity
65
+ include Neo4j::Rails::Persistence # handles how to save, create and update the model
66
+ include Neo4j::Rails::NodePersistence # handles how to save, create and update the model
67
+ include Neo4j::Rails::Attributes # handles how to save and retrieve attributes and override the property class method
68
+ include Neo4j::Rails::NestedAttributes
69
+ include Neo4j::Rails::HasN # allows some additional options on the #property class method
70
+ include Neo4j::Rails::Serialization # enable to_xml and to_json
71
+ include Neo4j::Rails::Validations # enable validations
72
+ include Neo4j::Rails::Callbacks # enable callbacks
73
+ include Neo4j::Rails::Timestamps # handle created_at, updated_at timestamp properties
74
+ include Neo4j::Rails::Finders # ActiveRecord style find
75
+ include Neo4j::Rails::Relationships # for none persisted relationships
76
+ include Neo4j::Rails::Compositions
77
+ include Neo4j::Rails::AcceptId
78
+ include Neo4j::Rails::Relationships
194
79
 
195
80
  # --------------------------------------
196
81
  # Public Class Methods
197
82
  # --------------------------------------
198
83
  class << self
199
- # NodeMixin overwrites the #new class method but it saves it as orig_new
200
- # Here, we just get it back to normal
201
- alias :new :orig_new
202
-
203
- def transaction(&block)
204
- Neo4j::Rails::Transaction.run do |tx|
205
- block.call(tx)
206
- end
207
- end
208
-
209
- def entity_load(id)
210
- Neo4j::Node.load(id)
211
- end
212
84
 
213
85
  ##
214
86
  # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling
215
87
  # dates and times from the database. This is set to :local by default.
88
+ # @api public
216
89
  def default_timezone
217
90
  @default_timezone || :local
218
91
  end
219
92
 
93
+ # @api public
220
94
  def default_timezone=(zone)
221
95
  @default_timezone = zone
222
96
  end
223
97
 
224
- def accepts_nested_attributes_for(*attr_names)
225
- options = attr_names.pop if attr_names[-1].is_a?(Hash)
226
-
227
- attr_names.each do |association_name|
228
- # Do some validation that we have defined the relationships we want to nest
229
- rel = self._decl_rels[association_name.to_sym]
230
- raise "No relationship declared with has_n or has_one with type #{association_name}" unless rel
231
- 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 rel.target_class
232
-
233
- if rel.has_one?
234
- send(:define_method, "#{association_name}_attributes=") do |attributes|
235
- update_nested_attributes(association_name.to_sym, attributes, options)
236
- end
237
- else
238
- send(:define_method, "#{association_name}_attributes=") do |attributes|
239
- if attributes.is_a?(Array)
240
- attributes.each do |attr|
241
- update_nested_attributes(association_name.to_sym, attr, options)
242
- end
243
- else
244
- attributes.each_value do |attr|
245
- update_nested_attributes(association_name.to_sym, attr, options)
246
- end
247
- end
248
- end
249
- end
250
-
251
- end
252
- end
253
-
254
- # When multitenancy is used, node should be findable only from current ref node.
255
- def findable?(entity)
256
- entity.is_a? self and entity.reachable_from_ref_node?
257
- end
258
-
259
98
  # Set the i18n scope to overwrite ActiveModel.
260
99
  #
261
100
  # @return [ Symbol ] :neo4j
101
+ # @api public
262
102
  def i18n_scope
263
103
  :neo4j
264
104
  end
265
105
  end
266
106
  end
267
-
268
- Model.class_eval do
269
- extend ActiveModel::Translation
270
-
271
- include Persistence # handles how to save, create and update the model
272
- include Attributes # handles how to save and retrieve attributes
273
- include Mapping::Property # allows some additional options on the #property class method
274
- include Serialization # enable to_xml and to_json
275
- include Validations # enable validations
276
- include Callbacks # enable callbacks
277
- include Timestamps # handle created_at, updated_at timestamp properties
278
- include ActiveModel::Observing # enable observers
279
- include Finders # ActiveRecord style find
280
- include Relationships # for none persisted relationships
281
- include Compositions
282
- include AcceptId
283
- end
284
107
  end
285
- end
108
+ end