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

Sign up to get free protection for your applications and to get access to all the features.
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