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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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