neo4j 1.0.0.beta.20 → 3.0.0.alpha.2

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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +243 -0
  3. data/CONTRIBUTORS +12 -0
  4. data/Gemfile +10 -11
  5. data/README.md +23 -0
  6. data/bin/neo4j-jars +33 -0
  7. data/config/locales/en.yml +5 -0
  8. data/config/neo4j/config.yml +98 -0
  9. data/lib/neo4j.rb +28 -68
  10. data/lib/neo4j/active_node.rb +60 -0
  11. data/lib/neo4j/active_node/callbacks.rb +41 -0
  12. data/lib/neo4j/active_node/has_n.rb +138 -0
  13. data/lib/neo4j/active_node/has_n/decl_rel.rb +236 -0
  14. data/lib/neo4j/active_node/has_n/nodes.rb +82 -0
  15. data/lib/neo4j/active_node/identity.rb +28 -0
  16. data/lib/neo4j/active_node/initialize.rb +24 -0
  17. data/lib/neo4j/active_node/labels.rb +142 -0
  18. data/lib/neo4j/active_node/persistence.rb +193 -0
  19. data/lib/neo4j/active_node/property.rb +41 -0
  20. data/lib/neo4j/active_node/rels.rb +11 -0
  21. data/lib/neo4j/active_node/validations.rb +51 -0
  22. data/lib/neo4j/railtie.rb +40 -0
  23. data/lib/neo4j/version.rb +1 -1
  24. data/lib/neo4j/wrapper.rb +25 -0
  25. data/neo4j.gemspec +25 -15
  26. metadata +136 -149
  27. data/README.rdoc +0 -135
  28. data/lib/generators/neo4j.rb +0 -65
  29. data/lib/generators/neo4j/model/model_generator.rb +0 -39
  30. data/lib/generators/neo4j/model/templates/model.erb +0 -7
  31. data/lib/neo4j/config.rb +0 -153
  32. data/lib/neo4j/database.rb +0 -56
  33. data/lib/neo4j/equal.rb +0 -21
  34. data/lib/neo4j/event_handler.rb +0 -116
  35. data/lib/neo4j/index/class_methods.rb +0 -62
  36. data/lib/neo4j/index/index.rb +0 -33
  37. data/lib/neo4j/index/indexer.rb +0 -312
  38. data/lib/neo4j/index/indexer_registry.rb +0 -68
  39. data/lib/neo4j/index/lucene_query.rb +0 -191
  40. data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  41. data/lib/neo4j/jars/lucene-core-3.0.2.jar +0 -0
  42. data/lib/neo4j/jars/neo4j-index-1.2-1.2.M03.jar +0 -0
  43. data/lib/neo4j/jars/neo4j-kernel-1.2-1.2.M03.jar +0 -0
  44. data/lib/neo4j/jars/neo4j-lucene-index-0.2-1.2.M03.jar +0 -0
  45. data/lib/neo4j/load.rb +0 -21
  46. data/lib/neo4j/mapping/class_methods/init_node.rb +0 -50
  47. data/lib/neo4j/mapping/class_methods/init_rel.rb +0 -35
  48. data/lib/neo4j/mapping/class_methods/property.rb +0 -80
  49. data/lib/neo4j/mapping/class_methods/relationship.rb +0 -90
  50. data/lib/neo4j/mapping/class_methods/root.rb +0 -31
  51. data/lib/neo4j/mapping/class_methods/rule.rb +0 -295
  52. data/lib/neo4j/mapping/decl_relationship_dsl.rb +0 -214
  53. data/lib/neo4j/mapping/has_n.rb +0 -83
  54. data/lib/neo4j/mapping/node_mixin.rb +0 -97
  55. data/lib/neo4j/mapping/relationship_mixin.rb +0 -117
  56. data/lib/neo4j/model.rb +0 -4
  57. data/lib/neo4j/neo4j.rb +0 -95
  58. data/lib/neo4j/node.rb +0 -131
  59. data/lib/neo4j/node_mixin.rb +0 -4
  60. data/lib/neo4j/node_relationship.rb +0 -149
  61. data/lib/neo4j/node_traverser.rb +0 -157
  62. data/lib/neo4j/property.rb +0 -111
  63. data/lib/neo4j/rails/finders.rb +0 -121
  64. data/lib/neo4j/rails/lucene_connection_closer.rb +0 -19
  65. data/lib/neo4j/rails/mapping/property.rb +0 -35
  66. data/lib/neo4j/rails/model.rb +0 -324
  67. data/lib/neo4j/rails/railtie.rb +0 -16
  68. data/lib/neo4j/rails/transaction.rb +0 -67
  69. data/lib/neo4j/rails/tx_methods.rb +0 -15
  70. data/lib/neo4j/rails/validations/non_nil.rb +0 -11
  71. data/lib/neo4j/rails/validations/uniqueness.rb +0 -31
  72. data/lib/neo4j/rails/value.rb +0 -124
  73. data/lib/neo4j/rails/value_properties.rb +0 -29
  74. data/lib/neo4j/relationship.rb +0 -169
  75. data/lib/neo4j/relationship_mixin.rb +0 -4
  76. data/lib/neo4j/relationship_traverser.rb +0 -92
  77. data/lib/neo4j/to_java.rb +0 -31
  78. data/lib/neo4j/transaction.rb +0 -68
  79. data/lib/neo4j/type_converters.rb +0 -98
@@ -0,0 +1,82 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+ module HasN
4
+
5
+ # The object created by a has_n or has_one Neo4j::NodeMixin class method which enables creating and traversal of nodes.
6
+ #
7
+ # @see Neo4j::ActiveNode::HasN::ClassMethods
8
+ class Nodes
9
+ include Enumerable
10
+
11
+ def initialize(node, decl_rel) # :nodoc:
12
+ @node = node
13
+ @decl_rel = decl_rel
14
+ end
15
+
16
+ def to_s
17
+ "HasN::Nodes [#{@decl_rel.dir}, id: #{@node.neo_id} type: #{@decl_rel.rel_type} decl_rel:#{@decl_rel}]"
18
+ end
19
+
20
+ # Traverse the relationship till the index position
21
+ # @return [Neo4j::ActiveMixin,Neo4j::Node,nil] the node at the given position
22
+ def [](index)
23
+ i = 0
24
+ each { |x| return x if i == index; i += 1 }
25
+ nil # out of index
26
+ end
27
+
28
+ # Pretend we are an array - this is necessarily for Rails actionpack/actionview/formhelper to work with this
29
+ def is_a?(type)
30
+ # ActionView requires this for nested attributes to work
31
+ return true if Array == type
32
+ super
33
+ end
34
+
35
+ # Required by the Enumerable mixin.
36
+ def each
37
+ @decl_rel.each_node(@node) { |n| yield n } # Should use yield here as passing &block through doesn't always work (why?)
38
+ end
39
+
40
+ # returns none wrapped nodes, you may get better performance using this method
41
+ def _each
42
+ @decl_rel._each_node(@node) { |n| yield n }
43
+ end
44
+
45
+ # Returns an real ruby array.
46
+ def to_ary
47
+ self.to_a
48
+ end
49
+
50
+ # Returns true if there are no node in this type of relationship
51
+ def empty?
52
+ first == nil
53
+ end
54
+
55
+
56
+ # Creates a relationship instance between this and the other node.
57
+ # Returns the relationship object
58
+ def create(other)
59
+ @decl_rel.create_relationship_to(@node, other)
60
+ end
61
+
62
+
63
+ # Creates a relationship between this and the other node.
64
+ #
65
+ # @example Person includes the Neo4j::NodeMixin and declares a has_n :friends
66
+ #
67
+ # p = Person.new # Node has declared having a friend type of relationship
68
+ # n1 = Node.new
69
+ # n2 = Node.new
70
+ #
71
+ # p.friends << n2 << n3
72
+ #
73
+ # @return self
74
+ def <<(other)
75
+ @decl_rel.create_relationship_to(@node, other)
76
+ self
77
+ end
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,28 @@
1
+ module Neo4j::ActiveNode
2
+ module Identity
3
+
4
+ def ==(o)
5
+ o.class == self.class && o.id == id
6
+ end
7
+ alias_method :eql?, :==
8
+
9
+ # Returns an Enumerable of all (primary) key attributes
10
+ # or nil if model.persisted? is false
11
+ def to_key
12
+ persisted? ? [id] : nil
13
+ end
14
+
15
+ # @return [Fixnum, nil] the neo4j id of the node if persisted or nil
16
+ def neo_id
17
+ _persisted_node ? _persisted_node.neo_id : nil
18
+ end
19
+
20
+ # @return [String, nil] same as #neo_id
21
+ def id
22
+ persisted? ? neo_id.to_s : nil
23
+ end
24
+
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,24 @@
1
+ module Neo4j::ActiveNode::Initialize
2
+ extend ActiveSupport::Concern
3
+
4
+ attr_reader :_persisted_node
5
+
6
+ # called when loading the node from the database
7
+ # @param [Neo4j::Node] persisted_node the node this class wraps
8
+ # @param [Hash] properties properties of the persisted node.
9
+ def init_on_load(persisted_node, properties)
10
+ @_persisted_node = persisted_node
11
+ @changed_attributes && @changed_attributes.clear
12
+ @attributes = attributes.merge(properties.stringify_keys)
13
+ end
14
+
15
+ # Implements the Neo4j::Node#wrapper and Neo4j::Relationship#wrapper method
16
+ # so that we don't have to care if the node is wrapped or not.
17
+ # @return self
18
+ def wrapper
19
+ self
20
+ end
21
+
22
+ end
23
+
24
+
@@ -0,0 +1,142 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+
4
+
5
+ # Provides a mapping between neo4j labels and Ruby classes
6
+ module Labels
7
+ extend ActiveSupport::Concern
8
+
9
+ WRAPPED_CLASSES = []
10
+
11
+ def labels
12
+ @_persisted_node.labels
13
+ end
14
+
15
+ def self.included(klass)
16
+ add_wrapped_class(klass)
17
+ end
18
+
19
+ def self.add_wrapped_class(klass)
20
+ _wrapped_classes << klass
21
+ @_wrapped_labels = nil
22
+ end
23
+
24
+
25
+ def self._wrapped_classes
26
+ Neo4j::ActiveNode::Labels::WRAPPED_CLASSES
27
+ end
28
+
29
+ protected
30
+
31
+ # Only for testing purpose
32
+ # @private
33
+ def self._wrapped_labels=(wl)
34
+ @_wrapped_labels=(wl)
35
+ end
36
+
37
+ def self._wrapped_labels
38
+ @_wrapped_labels ||= _wrapped_classes.inject({}) do |ack, clazz|
39
+ ack.tap do |a|
40
+ a[clazz.mapped_label_name.to_sym] = clazz if clazz.respond_to?(:mapped_label_name)
41
+ end
42
+ end
43
+ end
44
+
45
+ module ClassMethods
46
+
47
+ # Find all nodes/objects of this class, with given search criteria
48
+ # @param [Hash, nil] args the search critera or nil if finding all
49
+ # @param [Neo4j::Session] session defaults to the current
50
+ def all(args = nil, session = Neo4j::Session.current)
51
+ if (args)
52
+ find_by_hash(args, session)
53
+ else
54
+ Neo4j::Label.find_all_nodes(mapped_label_name, session)
55
+ end
56
+ end
57
+
58
+ # @return [Fixnum] number of nodes of this class
59
+ def count(session = Neo4j::Session.current)
60
+ q = session.query("MATCH (n:`#{mapped_label_name}`) RETURN count(n) AS count")
61
+ q.to_a[0][:count]
62
+ end
63
+
64
+ # Same as #all but return only one object
65
+ # If given a String or Fixnum it will return the object with that neo4j id.
66
+ # @param [Hash,String,Fixnum] args search criteria
67
+ def find(args, session = Neo4j::Session.current)
68
+ case args
69
+ when Hash
70
+ find_by_hash(args, session).first
71
+ when String, Fixnum
72
+ Neo4j::Node.load(args)
73
+ else
74
+ raise "Unknown argument #{args.class} in find method"
75
+ end
76
+ end
77
+
78
+
79
+ # Destroy all nodes an connected relationships
80
+ def destroy_all
81
+ Neo4j::Session.current._query("MATCH (n:`#{mapped_label_name}`)-[r]-() DELETE n,r")
82
+ Neo4j::Session.current._query("MATCH (n:`#{mapped_label_name}`) DELETE n")
83
+ end
84
+
85
+ # Creates a Neo4j index on given property
86
+ # @param [Symbol] property the property we want a Neo4j index on
87
+ def index(property)
88
+ if Neo4j::Session.current
89
+ _index(property)
90
+ else
91
+ Neo4j::Session.add_listener do |event, _|
92
+ _index(property) if event == :session_available
93
+ end
94
+ end
95
+ end
96
+
97
+
98
+ # @return [Array{Symbol}] all the labels that this class has
99
+ def mapped_label_names
100
+ self.ancestors.find_all { |a| a.respond_to?(:mapped_label_name) }.map { |a| a.mapped_label_name.to_sym }
101
+ end
102
+
103
+ # @return [Symbol] the label that this class has which corresponds to a Ruby class
104
+ def mapped_label_name
105
+ @_label_name || self.to_s.to_sym
106
+ end
107
+
108
+ def indexed_labels
109
+
110
+ end
111
+
112
+ protected
113
+
114
+ def find_by_hash(hash, session)
115
+ Neo4j::Label.query(mapped_label_name, {conditions: hash}, session)
116
+ end
117
+
118
+ def _index(property)
119
+ mapped_labels.each do |label|
120
+ # make sure the property is not indexed twice
121
+ existing = label.indexes[:property_keys]
122
+ label.create_index(property) unless existing.flatten.include?(property)
123
+ end
124
+ end
125
+
126
+ def mapped_labels
127
+ mapped_label_names.map{|label_name| Neo4j::Label.create(label_name)}
128
+ end
129
+
130
+ def mapped_label
131
+ Neo4j::Label.create(mapped_label_name)
132
+ end
133
+
134
+ def set_mapped_label_name(name)
135
+ @_label_name = name.to_sym
136
+ end
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,193 @@
1
+ module Neo4j::ActiveNode
2
+ module Persistence
3
+ class RecordInvalidError < RuntimeError
4
+ attr_reader :record
5
+
6
+ def initialize(record)
7
+ @record = record
8
+ super(@record.errors.full_messages.join(", "))
9
+ end
10
+ end
11
+
12
+ extend ActiveSupport::Concern
13
+
14
+ # Saves the model.
15
+ #
16
+ # If the model is new a record gets created in the database, otherwise the existing record gets updated.
17
+ # If perform_validation is true validations run.
18
+ # If any of them fail the action is cancelled and save returns false. If the flag is false validations are bypassed altogether. See ActiveRecord::Validations for more information.
19
+ # There’s a series of callbacks associated with save. If any of the before_* callbacks return false the action is cancelled and save returns false.
20
+ def save(*)
21
+ create_or_update
22
+ end
23
+
24
+ # Creates a model with values matching those of the instance attributes and returns its id.
25
+ # @private
26
+ # @return true
27
+ def create_model(*)
28
+ node = _create_node(props)
29
+ init_on_load(node, node.props)
30
+ # Neo4j::IdentityMap.add(node, self)
31
+ # write_changed_relationships
32
+ true
33
+ end
34
+
35
+ # Persist the object to the database. Validations and Callbacks are included
36
+ # by default but validation can be disabled by passing :validate => false
37
+ # to #save! Creates a new transaction.
38
+ #
39
+ # @raise a RecordInvalidError if there is a problem during save.
40
+ # @param (see Neo4j::Rails::Validations#save)
41
+ # @return nil
42
+ # @see #save
43
+ # @see Neo4j::Rails::Validations Neo4j::Rails::Validations - for the :validate parameter
44
+ # @see Neo4j::Rails::Callbacks Neo4j::Rails::Callbacks - for callbacks
45
+ def save!(*args)
46
+ unless save(*args)
47
+ raise RecordInvalidError.new(self)
48
+ end
49
+ end
50
+
51
+ def create_or_update
52
+ # since the same model can be created or updated twice from a relationship we have to have this guard
53
+ @_create_or_updating = true
54
+ result = persisted? ? update_model : create_model
55
+ unless result != false
56
+ Neo4j::Transaction.current.fail if Neo4j::Transaction.current
57
+ false
58
+ else
59
+ true
60
+ end
61
+ rescue => e
62
+ Neo4j::Transaction.current.fail if Neo4j::Transaction.current
63
+ raise e
64
+ ensure
65
+ @_create_or_updating = nil
66
+ end
67
+
68
+ def exist?
69
+ _persisted_node && _persisted_node.exist?
70
+ end
71
+
72
+ # Returns +true+ if the object was destroyed.
73
+ def destroyed?
74
+ @_deleted || (!new_record? && !exist?)
75
+ end
76
+
77
+ # Returns +true+ if the record is persisted, i.e. it’s not a new record and it was not destroyed
78
+ def persisted?
79
+ !new_record? && !destroyed?
80
+ end
81
+
82
+ # Returns +true+ if the record hasn't been saved to Neo4j yet.
83
+ def new_record?
84
+ ! _persisted_node
85
+ end
86
+
87
+ alias :new? :new_record?
88
+
89
+ def destroy
90
+ _persisted_node && _persisted_node.del
91
+ @_deleted = true
92
+ end
93
+
94
+ def update_model
95
+ if @changed_attributes && !@changed_attributes.empty?
96
+ changed_props = attributes.select{|k,v| @changed_attributes.include?(k)}
97
+ _persisted_node.props = changed_props
98
+ @changed_attributes.clear
99
+ end
100
+ end
101
+
102
+ def _create_node(*args)
103
+ session = Neo4j::Session.current
104
+ props = args[0] if args[0].is_a?(Hash)
105
+ labels = self.class.mapped_label_names
106
+ session.create_node(props, labels)
107
+ end
108
+
109
+ # @return [Hash] all defined and none nil properties
110
+ def props
111
+ attributes.reject{|k,v| v.nil?}.symbolize_keys
112
+ end
113
+
114
+ # @return true if the attributes hash has been frozen
115
+ def frozen?
116
+ freeze_if_deleted
117
+ @attributes.frozen?
118
+ end
119
+
120
+ def freeze
121
+ @attributes.freeze
122
+ self
123
+ end
124
+
125
+ def freeze_if_deleted
126
+ unless new_record?
127
+ # TODO - Neo4j::IdentityMap.remove_node_by_id(neo_id)
128
+ unless self.class.load_entity(neo_id)
129
+ @_deleted = true
130
+ freeze
131
+ end
132
+ end
133
+ end
134
+
135
+ def reload
136
+ return self if new_record?
137
+ @changed_attributes && @changed_attributes.clear
138
+ unless reload_from_database
139
+ @_deleted = true
140
+ freeze
141
+ end
142
+ self
143
+ end
144
+
145
+ def reload_from_database
146
+ # TODO - Neo4j::IdentityMap.remove_node_by_id(neo_id)
147
+ if reloaded = self.class.load_entity(neo_id)
148
+ send(:attributes=, reloaded.attributes)
149
+ end
150
+ reloaded
151
+ end
152
+
153
+ # Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved.
154
+ # If saving fails because the resource is invalid then false will be returned.
155
+ def update(attributes)
156
+ self.attributes = attributes
157
+ save
158
+ end
159
+ alias_method :update_attributes, :update
160
+
161
+ # Same as {#update_attributes}, but raises an exception if saving fails.
162
+ def update!(attributes)
163
+ self.attributes = attributes
164
+ save!
165
+ end
166
+ alias_method :update_attributes!, :update!
167
+
168
+ module ClassMethods
169
+ # Creates a saves a new node
170
+ # @param [Hash] props the properties the new node should have
171
+ def create(props = {})
172
+ new(props).tap do |obj|
173
+ obj.save
174
+ end
175
+ end
176
+
177
+ # Same as #create, but raises an error if there is a problem during save.
178
+ def create!(*args)
179
+ new(*args).tap do |o|
180
+ yield o if block_given?
181
+ o.save!
182
+ end
183
+ end
184
+
185
+ def load_entity(id)
186
+ Neo4j::Node.load(id)
187
+ end
188
+
189
+ end
190
+
191
+ end
192
+
193
+ end