neo4j 1.0.0.beta.21-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 (99) hide show
  1. data/CHANGELOG +141 -0
  2. data/CONTRIBUTORS +17 -0
  3. data/Gemfile +16 -0
  4. data/README.rdoc +135 -0
  5. data/lib/generators/neo4j.rb +65 -0
  6. data/lib/generators/neo4j/model/model_generator.rb +39 -0
  7. data/lib/generators/neo4j/model/templates/model.erb +7 -0
  8. data/lib/neo4j.rb +77 -0
  9. data/lib/neo4j/config.rb +153 -0
  10. data/lib/neo4j/database.rb +56 -0
  11. data/lib/neo4j/equal.rb +21 -0
  12. data/lib/neo4j/event_handler.rb +116 -0
  13. data/lib/neo4j/index/class_methods.rb +62 -0
  14. data/lib/neo4j/index/index.rb +33 -0
  15. data/lib/neo4j/index/indexer.rb +312 -0
  16. data/lib/neo4j/index/indexer_registry.rb +68 -0
  17. data/lib/neo4j/index/lucene_query.rb +191 -0
  18. data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  19. data/lib/neo4j/jars/lucene-core-3.0.2.jar +0 -0
  20. data/lib/neo4j/jars/neo4j-index-1.2-1.2.M03.jar +0 -0
  21. data/lib/neo4j/jars/neo4j-kernel-1.2-1.2.M03.jar +0 -0
  22. data/lib/neo4j/jars/neo4j-lucene-index-0.2-1.2.M03.jar +0 -0
  23. data/lib/neo4j/load.rb +21 -0
  24. data/lib/neo4j/mapping/class_methods/init_node.rb +50 -0
  25. data/lib/neo4j/mapping/class_methods/init_rel.rb +35 -0
  26. data/lib/neo4j/mapping/class_methods/list.rb +13 -0
  27. data/lib/neo4j/mapping/class_methods/property.rb +82 -0
  28. data/lib/neo4j/mapping/class_methods/relationship.rb +91 -0
  29. data/lib/neo4j/mapping/class_methods/rule.rb +295 -0
  30. data/lib/neo4j/mapping/decl_relationship_dsl.rb +214 -0
  31. data/lib/neo4j/mapping/has_list.rb +134 -0
  32. data/lib/neo4j/mapping/has_n.rb +83 -0
  33. data/lib/neo4j/mapping/node_mixin.rb +112 -0
  34. data/lib/neo4j/mapping/relationship_mixin.rb +120 -0
  35. data/lib/neo4j/model.rb +4 -0
  36. data/lib/neo4j/neo4j.rb +95 -0
  37. data/lib/neo4j/node.rb +131 -0
  38. data/lib/neo4j/node_mixin.rb +4 -0
  39. data/lib/neo4j/node_relationship.rb +149 -0
  40. data/lib/neo4j/node_traverser.rb +157 -0
  41. data/lib/neo4j/property.rb +111 -0
  42. data/lib/neo4j/rails/attributes.rb +155 -0
  43. data/lib/neo4j/rails/callbacks.rb +34 -0
  44. data/lib/neo4j/rails/finders.rb +134 -0
  45. data/lib/neo4j/rails/lucene_connection_closer.rb +19 -0
  46. data/lib/neo4j/rails/mapping/property.rb +60 -0
  47. data/lib/neo4j/rails/model.rb +105 -0
  48. data/lib/neo4j/rails/persistence.rb +260 -0
  49. data/lib/neo4j/rails/railtie.rb +21 -0
  50. data/lib/neo4j/rails/relationships/mapper.rb +96 -0
  51. data/lib/neo4j/rails/relationships/relationship.rb +30 -0
  52. data/lib/neo4j/rails/relationships/relationships.rb +60 -0
  53. data/lib/neo4j/rails/serialization.rb +25 -0
  54. data/lib/neo4j/rails/timestamps.rb +65 -0
  55. data/lib/neo4j/rails/transaction.rb +67 -0
  56. data/lib/neo4j/rails/tx_methods.rb +15 -0
  57. data/lib/neo4j/rails/validations.rb +38 -0
  58. data/lib/neo4j/rails/validations/non_nil.rb +11 -0
  59. data/lib/neo4j/rails/validations/uniqueness.rb +37 -0
  60. data/lib/neo4j/relationship.rb +169 -0
  61. data/lib/neo4j/relationship_mixin.rb +4 -0
  62. data/lib/neo4j/relationship_traverser.rb +92 -0
  63. data/lib/neo4j/to_java.rb +31 -0
  64. data/lib/neo4j/transaction.rb +68 -0
  65. data/lib/neo4j/type_converters.rb +117 -0
  66. data/lib/neo4j/version.rb +3 -0
  67. data/lib/orm_adapter/adapters/neo4j.rb +55 -0
  68. data/lib/tmp/neo4j/active_tx_log +1 -0
  69. data/lib/tmp/neo4j/index/lucene-store.db +0 -0
  70. data/lib/tmp/neo4j/index/lucene.log.active +0 -0
  71. data/lib/tmp/neo4j/lucene-fulltext/lucene-store.db +0 -0
  72. data/lib/tmp/neo4j/lucene-fulltext/lucene.log.active +0 -0
  73. data/lib/tmp/neo4j/lucene/lucene-store.db +0 -0
  74. data/lib/tmp/neo4j/lucene/lucene.log.active +0 -0
  75. data/lib/tmp/neo4j/messages.log +85 -0
  76. data/lib/tmp/neo4j/neostore +0 -0
  77. data/lib/tmp/neo4j/neostore.id +0 -0
  78. data/lib/tmp/neo4j/neostore.nodestore.db +0 -0
  79. data/lib/tmp/neo4j/neostore.nodestore.db.id +0 -0
  80. data/lib/tmp/neo4j/neostore.propertystore.db +0 -0
  81. data/lib/tmp/neo4j/neostore.propertystore.db.arrays +0 -0
  82. data/lib/tmp/neo4j/neostore.propertystore.db.arrays.id +0 -0
  83. data/lib/tmp/neo4j/neostore.propertystore.db.id +0 -0
  84. data/lib/tmp/neo4j/neostore.propertystore.db.index +0 -0
  85. data/lib/tmp/neo4j/neostore.propertystore.db.index.id +0 -0
  86. data/lib/tmp/neo4j/neostore.propertystore.db.index.keys +0 -0
  87. data/lib/tmp/neo4j/neostore.propertystore.db.index.keys.id +0 -0
  88. data/lib/tmp/neo4j/neostore.propertystore.db.strings +0 -0
  89. data/lib/tmp/neo4j/neostore.propertystore.db.strings.id +0 -0
  90. data/lib/tmp/neo4j/neostore.relationshipstore.db +0 -0
  91. data/lib/tmp/neo4j/neostore.relationshipstore.db.id +0 -0
  92. data/lib/tmp/neo4j/neostore.relationshiptypestore.db +0 -0
  93. data/lib/tmp/neo4j/neostore.relationshiptypestore.db.id +0 -0
  94. data/lib/tmp/neo4j/neostore.relationshiptypestore.db.names +0 -0
  95. data/lib/tmp/neo4j/neostore.relationshiptypestore.db.names.id +0 -0
  96. data/lib/tmp/neo4j/nioneo_logical.log.active +0 -0
  97. data/lib/tmp/neo4j/tm_tx_log.1 +0 -0
  98. data/neo4j.gemspec +31 -0
  99. metadata +216 -0
@@ -0,0 +1,157 @@
1
+ module Neo4j
2
+
3
+ class PruneEvaluator # :nodoc:
4
+ include org.neo4j.graphdb.traversal.PruneEvaluator
5
+ def initialize(proc)
6
+ @proc = proc
7
+ end
8
+
9
+ def prune_after(path)
10
+ @proc.call(path)
11
+ end
12
+ end
13
+
14
+ class FilterPredicate # :nodoc:
15
+ include org.neo4j.helpers.Predicate
16
+ def initialize
17
+ @procs = []
18
+ end
19
+
20
+ def add(proc)
21
+ @procs << proc
22
+ end
23
+
24
+ def include_start_node
25
+ @include_start_node = true
26
+ end
27
+
28
+ def accept(path)
29
+ return false if @include_start_node && path.length == 0
30
+ # find the first filter which returns false
31
+ # if not found then we will accept this path
32
+ @procs.find {|p| !p.call(path)}.nil?
33
+ end
34
+ end
35
+
36
+
37
+ class NodeTraverser
38
+ include Enumerable
39
+ include ToJava
40
+
41
+ def initialize(from, type = nil, dir=nil)
42
+ @from = from
43
+ @depth = 1
44
+ if type.nil? || dir.nil?
45
+ @td = org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl.new.breadth_first()
46
+ else
47
+ @type = type_to_java(type)
48
+ @dir = dir_to_java(dir)
49
+ @td = org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl.new.breadth_first().relationships(@type, @dir)
50
+ end
51
+ end
52
+
53
+
54
+ def to_s
55
+ "NodeTraverser [from: #{@from.neo_id} depth: #{@depth} type: #{@type} dir:#{@dir}"
56
+ end
57
+
58
+ def <<(other_node)
59
+ new(other_node)
60
+ self
61
+ end
62
+
63
+ def new(other_node)
64
+ case @dir
65
+ when org.neo4j.graphdb.Direction::OUTGOING
66
+ @from.create_relationship_to(other_node, @type)
67
+ when org.neo4j.graphdb.Direction::INCOMING
68
+ other_node._java_node.create_relationship_to(@from, @type)
69
+ else
70
+ raise "Only allowed to create outgoing or incoming relationships (not #@dir)"
71
+ end
72
+ end
73
+
74
+ def both(type)
75
+ @type = type_to_java(type) if type
76
+ @dir = dir_to_java(:both)
77
+ @td = @td.relationships(type_to_java(type), @dir)
78
+ self
79
+ end
80
+
81
+ def outgoing(type)
82
+ @type = type_to_java(type) if type
83
+ @dir = dir_to_java(:outgoing)
84
+ @td = @td.relationships(type_to_java(type), @dir)
85
+ self
86
+ end
87
+
88
+ def incoming(type)
89
+ @type = type_to_java(type) if type
90
+ @dir = dir_to_java(:incoming)
91
+ @td = @td.relationships(type_to_java(type), @dir)
92
+ self
93
+ end
94
+
95
+ def filter_method(name, &proc)
96
+ # add method name
97
+ singelton = class << self; self; end
98
+ singelton.send(:define_method, name) {filter &proc}
99
+ self
100
+ end
101
+
102
+ def prune(&block)
103
+ @td = @td.prune(PruneEvaluator.new(block))
104
+ self
105
+ end
106
+
107
+ def filter(&block)
108
+ # we keep a reference to filter predicate since only one filter is allowed and we might want to modify it
109
+ @filter_predicate ||= FilterPredicate.new
110
+ @filter_predicate.add(block)
111
+ @td = @td.filter(@filter_predicate)
112
+ self
113
+ end
114
+
115
+ # Sets depth, if :all then it will traverse any depth
116
+ def depth(d)
117
+ @depth = d
118
+ self
119
+ end
120
+
121
+ def include_start_node
122
+ @include_start_node = true
123
+ self
124
+ end
125
+
126
+ def size
127
+ [*self].size
128
+ end
129
+
130
+ alias_method :length, :size
131
+
132
+ def [](index)
133
+ each_with_index {|node,i| break node if index == i}
134
+ end
135
+
136
+ def empty?
137
+ first == nil
138
+ end
139
+
140
+ def each
141
+ iterator.each {|i| yield i.wrapper}
142
+ end
143
+
144
+ def iterator
145
+ unless @include_start_node
146
+ if @filter_predicate
147
+ @filter_predicate.include_start_node
148
+ else
149
+ @td = @td.filter(org.neo4j.kernel.Traversal.return_all_but_start_node)
150
+ end
151
+ end
152
+ @td = @td.prune(org.neo4j.kernel.Traversal.pruneAfterDepth( @depth ) ) unless @depth == :all
153
+ @td.traverse(@from).nodes
154
+ end
155
+ end
156
+
157
+ end
@@ -0,0 +1,111 @@
1
+ module Neo4j
2
+ module Property
3
+
4
+ # Returns a hash of all properties
5
+ # It also include the id of the node with the key <tt>_neo_id</tt>
6
+ #
7
+ def props
8
+ ret = {"_neo_id" => neo_id}
9
+ iter = getPropertyKeys.iterator
10
+ while (iter.hasNext) do
11
+ key = iter.next
12
+ ret[key] = get_property(key)
13
+ end
14
+ ret
15
+ end
16
+
17
+ # Returns the unique id of this node.
18
+ # Ids are garbage collected over time so they are only guaranteed to be unique during a specific time span:
19
+ # if the node is deleted, it's likely that a new node at some point will get the old id. Note:
20
+ # this makes node ids brittle as public APIs.
21
+ def neo_id
22
+ getId
23
+ end
24
+
25
+ # Returns a hash of properties with keys not starting with <tt>_</tt>
26
+ # That means that the neo_id will not be included in the returned hash.
27
+ #
28
+ def attributes
29
+ attr = props
30
+ ret = {}
31
+ attr.each_pair { |k, v| ret[k] = wrapper.respond_to?(k) ? wrapper.send(k) : v unless k.to_s[0] == ?_ }
32
+ ret
33
+ end
34
+
35
+ # Checks if the given key exist as a property.
36
+ def property?(key)
37
+ has_property?(key.to_s)
38
+ end
39
+
40
+ # Updates this node/relationship's properties by using the provided struct/hash.
41
+ # If the option <code>{:strict => true}</code> is given, any properties present on
42
+ # the node but not present in the hash will be removed from the node.
43
+ #
44
+ # ==== Parameters
45
+ # struct_or_hash:: the key and value to be set, should respond to <tt>each_pair</tt>
46
+ # options:: further options defining the context of the update, should be a Hash
47
+ #
48
+ # ==== Returns
49
+ # self
50
+ #
51
+ def update(struct_or_hash, options={})
52
+ strict = options[:strict]
53
+ keys_to_delete = props.keys - %w(_neo_id _classname) if strict
54
+ struct_or_hash.each_pair do |key, value|
55
+ next if %w(_neo_id _classname).include? key.to_s
56
+ # do not allow special properties to be mass assigned
57
+ keys_to_delete.delete(key) if strict
58
+ setter_meth = "#{key}=".to_sym
59
+ if @_wrapper && @_wrapper.respond_to?(setter_meth)
60
+ @_wrapper.send(setter_meth, value)
61
+ else
62
+ self[key] = value
63
+ end
64
+ end
65
+ keys_to_delete.each { |key| delete_property(key) } if strict
66
+ self
67
+ end
68
+
69
+
70
+ # Returns the value of the given key or nil if the property does not exist.
71
+ def [](key)
72
+ return unless property?(key)
73
+ val = get_property(key.to_s)
74
+ val.class.superclass == ArrayJavaProxy ? val.to_a : val
75
+ end
76
+
77
+ # Sets the property of this node.
78
+ # Property keys are always strings. Valid property value types are the primitives(<tt>String</tt>, <tt>Fixnum</tt>, <tt>Float</tt>, <tt>FalseClass</tt>, <tt>TrueClass</tt>) or array of those primitives.
79
+ #
80
+ # ==== Gotchas
81
+ # * Values in the array must be of the same type.
82
+ # * You can *not* delete or add one item in the array (e.g. person.phones.delete('123')) but instead you must create a new array instead.
83
+ #
84
+ def []=(key, value)
85
+ k = key.to_s
86
+ if value.nil?
87
+ remove_property(k)
88
+ elsif (Array === value)
89
+ case value[0]
90
+ when NilClass
91
+ set_property(k, [].to_java(:string))
92
+ when String
93
+ set_property(k, value.to_java(:string))
94
+ when Float
95
+ set_property(k, value.to_java(:double))
96
+ when FalseClass, TrueClass
97
+ set_property(k, value.to_java(:boolean))
98
+ when Fixnum
99
+ set_property(k, value.to_java(:long))
100
+ when Boolean
101
+ set_property(k, value.to_java(:boolean))
102
+ else
103
+ raise "Not allowed to store array with value #{value[0]} type #{value[0].class}"
104
+ end
105
+ else
106
+ set_property(k, value)
107
+ end
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,155 @@
1
+ # This module handles the getting, setting and updating of attributes or properties
2
+ # in a Railsy way. This typically means not writing anything to the DB until the
3
+ # object is saved (after validation).
4
+ #
5
+ # Externally, when we talk about properties (e.g. #property?, #property_names, #properties),
6
+ # we mean all of the stored properties for this object include the 'hidden' props
7
+ # with underscores at the beginning such as _neo_id and _classname. When we talk
8
+ # about attributes, we mean all the properties apart from those hidden ones.
9
+ module Neo4j
10
+ module Rails
11
+ module Attributes
12
+ extend ActiveSupport::Concern
13
+
14
+ included do
15
+ include ActiveModel::Dirty # track changes to attributes
16
+ include ActiveModel::MassAssignmentSecurity # handle attribute hash assignment
17
+
18
+ class_inheritable_hash :attribute_defaults
19
+ self.attribute_defaults ||= {}
20
+
21
+ # save the original [] and []= to use as read/write to Neo4j
22
+ alias_method :read_attribute, :[]
23
+ alias_method :write_attribute, :[]=
24
+
25
+ # wrap the read/write in type conversion
26
+ alias_method_chain :read_local_property, :type_conversion
27
+ alias_method_chain :write_local_property, :type_conversion
28
+
29
+ # whenever we refer to [] or []=. use our local properties store
30
+ alias_method :[], :read_local_property
31
+ alias_method :[]=, :write_local_property
32
+ end
33
+
34
+ # The behaviour of []= changes with a Rails Model, where nothing gets written
35
+ # to Neo4j until the object is saved, during which time all the validations
36
+ # and callbacks are run to ensure correctness
37
+ def write_local_property(key, value)
38
+ key_s = key.to_s
39
+ if @properties[key_s] != value
40
+ attribute_will_change!(key_s)
41
+ @properties[key_s] = value
42
+ end
43
+ value
44
+ end
45
+
46
+ # Returns the locally stored value for the key or retrieves the value from
47
+ # the DB if we don't have one
48
+ def read_local_property(key)
49
+ key = key.to_s
50
+ if @properties.has_key?(key)
51
+ @properties[key]
52
+ else
53
+ @properties[key] = (persisted? && _java_node.has_property?(key)) ? read_attribute(key) : attribute_defaults[key]
54
+ end
55
+ end
56
+
57
+ # Mass-assign attributes. Stops any protected attributes from being assigned.
58
+ def attributes=(attributes, guard_protected_attributes = true)
59
+ attributes = sanitize_for_mass_assignment(attributes) if guard_protected_attributes
60
+ attributes.each { |k, v| respond_to?("#{k}=") ? send("#{k}=", v) : self[k] = v }
61
+ end
62
+
63
+ # Tracks the current changes and clears the changed attributes hash. Called
64
+ # after saving the object.
65
+ def clear_changes
66
+ @previously_changed = changes
67
+ @changed_attributes.clear
68
+ end
69
+
70
+ # Return the properties from the Neo4j Node, merged with those that haven't
71
+ # yet been saved
72
+ def props
73
+ ret = {}
74
+ property_names.each do |property_name|
75
+ ret[property_name] = respond_to?(property_name) ? send(property_name) : send(:[], property_name)
76
+ end
77
+ ret
78
+ end
79
+
80
+ # Return all the attributes for this model as a hash attr => value. Doesn't
81
+ # include properties that start with <tt>_</tt>.
82
+ def attributes
83
+ ret = {}
84
+ attribute_names.each do |attribute_name|
85
+ ret[attribute_name] = respond_to?(attribute_name) ? send(attribute_name) : send(:[], attribute_name)
86
+ end
87
+ ret
88
+ end
89
+
90
+ # Known properties are either in the @properties, the declared
91
+ # attributes or the property keys for the persisted node.
92
+ def property_names
93
+ keys = @properties.keys + self.class._decl_props.keys.map { |k| k.to_s }
94
+ keys += _java_node.property_keys.to_a if persisted?
95
+ keys.flatten.uniq
96
+ end
97
+
98
+ # Known attributes are either in the @properties, the declared
99
+ # attributes or the property keys for the persisted node. Any attributes
100
+ # that start with <tt>_</tt> are rejected
101
+ def attribute_names
102
+ property_names.reject { |property_name| property_name[0] == ?_ }
103
+ end
104
+
105
+ # Known properties are either in the @properties, the declared
106
+ # properties or the property keys for the persisted node
107
+ def property?(name)
108
+ @properties.keys.include?(name) ||
109
+ self.class._decl_props.map { |k| k.to_s }.include?(name) ||
110
+ begin
111
+ super
112
+ rescue org.neo4j.graphdb.NotFoundException
113
+ set_deleted_properties
114
+ nil
115
+ end
116
+ end
117
+
118
+ # Return true if method_name is the name of an appropriate attribute
119
+ # method
120
+ def attribute?(name)
121
+ name[0] != ?_ && property?(name)
122
+ end
123
+
124
+ # To get ActiveModel::Dirty to work, we need to be able to call undeclared
125
+ # properties as though they have get methods
126
+ def method_missing(method_id, *args, &block)
127
+ method_name = method_id.to_s
128
+ if property?(method_name)
129
+ self[method_name]
130
+ else
131
+ super
132
+ end
133
+ end
134
+
135
+ def respond_to?(method_id, include_private = false)
136
+ method_name = method_id.to_s
137
+ if property?(method_name)
138
+ true
139
+ else
140
+ super
141
+ end
142
+ end
143
+
144
+ # Wrap the getter in a conversion from Java to Ruby
145
+ def read_local_property_with_type_conversion(property)
146
+ Neo4j::TypeConverters.to_ruby(self.class, property, read_local_property_without_type_conversion(property))
147
+ end
148
+
149
+ # Wrap the setter in a conversion from Ruby to Java
150
+ def write_local_property_with_type_conversion(property, value)
151
+ write_local_property_without_type_conversion(property, Neo4j::TypeConverters.to_java(self.class, property, value))
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,34 @@
1
+ module Neo4j
2
+ module Rails
3
+ module Callbacks
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ [:create_or_update, :create, :update, :destroy].each do |method|
8
+ alias_method_chain method, :callbacks
9
+ end
10
+
11
+ extend ActiveModel::Callbacks
12
+
13
+ define_model_callbacks :create, :save, :update, :destroy
14
+ end
15
+
16
+ def destroy_with_callbacks #:nodoc:
17
+ _run_destroy_callbacks { destroy_without_callbacks }
18
+ end
19
+
20
+ private
21
+ def create_or_update_with_callbacks #:nodoc:
22
+ _run_save_callbacks { create_or_update_without_callbacks }
23
+ end
24
+
25
+ def create_with_callbacks #:nodoc:
26
+ _run_create_callbacks { create_without_callbacks }
27
+ end
28
+
29
+ def update_with_callbacks(*) #:nodoc:
30
+ _run_update_callbacks { update_without_callbacks }
31
+ end
32
+ end
33
+ end
34
+ end