neo4j-core 3.0.0.alpha.1

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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +22 -0
  3. data/README.md +332 -0
  4. data/lib/neo4j-core.rb +27 -0
  5. data/lib/neo4j-core/cypher_translator.rb +34 -0
  6. data/lib/neo4j-core/hash_with_indifferent_access.rb +165 -0
  7. data/lib/neo4j-core/helpers.rb +25 -0
  8. data/lib/neo4j-core/label.rb +8 -0
  9. data/lib/neo4j-core/version.rb +5 -0
  10. data/lib/neo4j-embedded.rb +18 -0
  11. data/lib/neo4j-embedded/embedded_database.rb +29 -0
  12. data/lib/neo4j-embedded/embedded_label.rb +80 -0
  13. data/lib/neo4j-embedded/embedded_node.rb +163 -0
  14. data/lib/neo4j-embedded/embedded_relationship.rb +44 -0
  15. data/lib/neo4j-embedded/embedded_session.rb +151 -0
  16. data/lib/neo4j-embedded/property.rb +43 -0
  17. data/lib/neo4j-embedded/to_java.rb +49 -0
  18. data/lib/neo4j-server.rb +10 -0
  19. data/lib/neo4j-server/cypher_label.rb +28 -0
  20. data/lib/neo4j-server/cypher_node.rb +140 -0
  21. data/lib/neo4j-server/cypher_node_uncommited.rb +12 -0
  22. data/lib/neo4j-server/cypher_relationship.rb +82 -0
  23. data/lib/neo4j-server/cypher_response.rb +113 -0
  24. data/lib/neo4j-server/cypher_session.rb +156 -0
  25. data/lib/neo4j-server/cypher_transaction.rb +81 -0
  26. data/lib/neo4j-server/resource.rb +73 -0
  27. data/lib/neo4j/entity_equality.rb +9 -0
  28. data/lib/neo4j/jars/concurrentlinkedhashmap-lru-1.3.1.jar +0 -0
  29. data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  30. data/lib/neo4j/jars/lucene-core-3.6.2.jar +0 -0
  31. data/lib/neo4j/jars/neo4j-cypher-2.0.0-M06.jar +0 -0
  32. data/lib/neo4j/jars/neo4j-kernel-2.0-SNAPSHOT-tests.jar +0 -0
  33. data/lib/neo4j/jars/neo4j-kernel-2.0.0-M06.jar +0 -0
  34. data/lib/neo4j/jars/neo4j-lucene-index-2.0.0-M06.jar +0 -0
  35. data/lib/neo4j/jars/neo4j-management-2.0.0-M06.jar +0 -0
  36. data/lib/neo4j/jars/org.apache.servicemix.bundles.jline-0.9.94_1.jar +0 -0
  37. data/lib/neo4j/jars/parboiled-core-1.1.6.jar +0 -0
  38. data/lib/neo4j/jars/parboiled-scala_2.10-1.1.6.jar +0 -0
  39. data/lib/neo4j/jars/scala-library-2.10.2.jar +0 -0
  40. data/lib/neo4j/label.rb +88 -0
  41. data/lib/neo4j/node.rb +185 -0
  42. data/lib/neo4j/property_container.rb +22 -0
  43. data/lib/neo4j/property_validator.rb +23 -0
  44. data/lib/neo4j/relationship.rb +84 -0
  45. data/lib/neo4j/session.rb +124 -0
  46. data/lib/neo4j/tasks/neo4j_server.rb +131 -0
  47. data/lib/neo4j/transaction.rb +52 -0
  48. data/neo4j-core.gemspec +35 -0
  49. metadata +144 -0
@@ -0,0 +1,25 @@
1
+ module Neo4j::Core
2
+ # wrapps Neo4j ResourceIterator, automatically close it
3
+
4
+ module ArgumentHelper
5
+
6
+ def self.session(args)
7
+ args.last.kind_of?(Neo4j::Session) ? args.pop : Neo4j::Session.current
8
+ end
9
+ end
10
+
11
+ module TxMethods
12
+ def tx_methods(*methods)
13
+ methods.each do |method|
14
+ tx_method = "#{method}_in_tx"
15
+ send(:alias_method, tx_method, method)
16
+ send(:define_method, method) do |*args, &block|
17
+ session = ArgumentHelper.session(args)
18
+ Neo4j::Transaction.run(session.auto_commit?) { send(tx_method, *args, &block) }
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ end
@@ -0,0 +1,8 @@
1
+ module Neo4j::Core
2
+ class Label
3
+ def labels
4
+ get_labels.map{|x| Label.new(x.name) }
5
+ end
6
+ end
7
+
8
+ end
@@ -0,0 +1,5 @@
1
+ module Neo4j
2
+ module Core
3
+ VERSION = "3.0.0.alpha.1"
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ require 'java'
2
+
3
+ # TODO: release neo4j-community jar 2.0
4
+ # Load Neo4j Jars for the jars folder
5
+ jar_folder = File.expand_path('../neo4j/jars', __FILE__)
6
+ jars = Dir.new(jar_folder).entries.find_all { |x| x =~ /\.jar$/ }
7
+ jars.each { |jar| require File.expand_path(jar, jar_folder) }
8
+
9
+ require 'neo4j-embedded/to_java'
10
+ require 'neo4j-embedded/property'
11
+ require 'neo4j-embedded/embedded_session'
12
+ require 'neo4j-embedded/embedded_label'
13
+ require 'neo4j-embedded/embedded_node'
14
+ require 'neo4j-embedded/embedded_relationship'
15
+ require 'neo4j-embedded/embedded_label'
16
+
17
+ # TODO replace this with https://github.com/intridea/hashie gem
18
+ require 'neo4j-core/hash_with_indifferent_access'
@@ -0,0 +1,29 @@
1
+ module Neo4j::Embedded
2
+ class EmbeddedDatabase
3
+
4
+ class Error < StandardError
5
+ end
6
+
7
+ class << self
8
+ def connect(db_location, config={})
9
+ if Neo4j::Session.current.respond_to?(:db_location) && Neo4j::Session.current.db_location == db_location
10
+ return Neo4j::Session.current
11
+ else
12
+ EmbeddedSession.new(db_location, config)
13
+ end
14
+ end
15
+
16
+ def create_db(db_location)
17
+ puts "Start embedded Neo4j db at #{db_location}"
18
+ factory = Java::OrgNeo4jGraphdbFactory::GraphDatabaseFactory.new
19
+ factory.newEmbeddedDatabase(db_location)
20
+ end
21
+
22
+ def factory_class
23
+ Java::OrgNeo4jGraphdbFactory::GraphDatabaseFactory
24
+ Java::OrgNeo4jTest::ImpermanentGraphDatabase
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,80 @@
1
+ module Neo4j::Embedded
2
+ class EmbeddedLabel
3
+ extend Neo4j::Core::TxMethods
4
+ attr_reader :name
5
+ JAVA_CLASS = Java::OrgNeo4jGraphdb::DynamicLabel
6
+
7
+ def initialize(session, name)
8
+ @name = name.to_sym
9
+ @session = session
10
+ end
11
+
12
+ def to_s
13
+ @name
14
+ end
15
+
16
+ def find_nodes(key=nil, value=nil)
17
+ begin
18
+ iterator = _find_nodes(key,value)
19
+ iterator.to_a.map{|n| n.wrapper}
20
+ ensure
21
+ iterator && iterator.close
22
+ end
23
+ end
24
+ tx_methods :find_nodes
25
+
26
+ def _find_nodes(key=nil, value=nil)
27
+ if (key)
28
+ @session.graph_db.find_nodes_by_label_and_property(as_java, key, value).iterator
29
+ else
30
+ ggo = Java::OrgNeo4jTooling::GlobalGraphOperations.at(@session.graph_db)
31
+ ggo.getAllNodesWithLabel(as_java).iterator
32
+ end
33
+
34
+ end
35
+
36
+ def as_java
37
+ self.class.as_java(@name.to_s)
38
+ end
39
+
40
+ def create_index(*properties)
41
+ index_creator = @session.graph_db.schema.index_for(as_java)
42
+ # we can also use the PropertyConstraintCreator here
43
+ properties.inject(index_creator) {|creator, key| creator.on(key.to_s)}.create
44
+ end
45
+ tx_methods :create_index
46
+
47
+ def indexes()
48
+ {
49
+ property_keys: @session.graph_db.schema.indexes(as_java).map do |index_def|
50
+ index_def.property_keys.map{|x| x.to_sym}
51
+ end
52
+ }
53
+ end
54
+ tx_methods :indexes
55
+
56
+ def drop_index(*properties)
57
+ @session.graph_db.schema.indexes(as_java).each do |index_def|
58
+ # at least one match, TODO
59
+ keys = index_def.property_keys.map{|x| x.to_sym}
60
+ index_def.drop if (properties - keys).count < properties.count
61
+ end
62
+
63
+ end
64
+ tx_methods :drop_index
65
+
66
+ class << self
67
+
68
+ def as_java(labels)
69
+ if labels.is_a?(Array)
70
+ return nil if labels.empty?
71
+ labels.inject([]) { |result, label| result << JAVA_CLASS.label(label.to_s) }.to_java(JAVA_CLASS)
72
+ else
73
+ JAVA_CLASS.label(labels.to_s)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ end
80
+
@@ -0,0 +1,163 @@
1
+ module Neo4j::Embedded
2
+ class RelsIterator
3
+ include Enumerable
4
+ extend Neo4j::Core::TxMethods
5
+
6
+ def initialize(node, match)
7
+ @node = node
8
+ @match = match
9
+ end
10
+
11
+ def each(&block)
12
+ @node._rels(@match).each {|r| block.call(r)}
13
+ end
14
+ tx_methods :each
15
+
16
+ def empty?
17
+ first == nil
18
+ end
19
+
20
+ end
21
+
22
+ class NodesIterator
23
+ include Enumerable
24
+ extend Neo4j::Core::TxMethods
25
+
26
+ def initialize(node, match)
27
+ @node = node
28
+ @match = match
29
+ end
30
+
31
+ def each(&block)
32
+ @node._rels(@match).each {|r| block.call(r.other_node(@node))}
33
+ end
34
+ tx_methods :each
35
+
36
+ def empty?
37
+ first == nil
38
+ end
39
+
40
+ end
41
+
42
+ class EmbeddedNode
43
+ class << self
44
+ # This method is used to extend a Java Neo4j class so that it includes the same mixins as this class.
45
+ def extend_java_class(java_clazz)
46
+ java_clazz.class_eval do
47
+ include Neo4j::Embedded::Property
48
+ include Neo4j::EntityEquality
49
+ extend Neo4j::Core::TxMethods
50
+
51
+ def exist?
52
+ !!graph_database.get_node_by_id(neo_id)
53
+ rescue Java::OrgNeo4jGraphdb.NotFoundException
54
+ nil
55
+ end
56
+ tx_methods :exist?
57
+
58
+ def labels
59
+ iterator = _labels.iterator
60
+ iterator.to_a.map{|x| x.name.to_sym}
61
+ ensure
62
+ iterator && iterator.close
63
+ end
64
+ tx_methods :labels
65
+
66
+ alias_method :_labels, :getLabels
67
+
68
+ def del
69
+ _rels.each { |r| r.del }
70
+ delete
71
+ nil
72
+ end
73
+ tx_methods :del
74
+
75
+ def create_rel(type, other_node, props = nil)
76
+ rel = create_relationship_to(other_node, ToJava.type_to_java(type))
77
+ props.each_pair { |k, v| rel[k] = v } if props
78
+ rel
79
+ end
80
+ tx_methods :create_rel
81
+
82
+
83
+ def rels(match={})
84
+ RelsIterator.new(self, match)
85
+ end
86
+
87
+ def nodes(match={})
88
+ NodesIterator.new(self, match)
89
+ end
90
+
91
+ def node(match={})
92
+ rel = _rel(match)
93
+ rel && rel.other_node(self)
94
+ end
95
+ tx_methods :node
96
+
97
+ def rel?(match={})
98
+ _rels(match).has_next
99
+ end
100
+ tx_methods :rel?
101
+
102
+ def rel(match={})
103
+ _rel(match)
104
+ end
105
+ tx_methods :rel
106
+
107
+ def _rel(match={})
108
+ dir = match[:dir] || :both
109
+ rel_type = match[:type]
110
+
111
+ rel = if rel_type
112
+ get_single_relationship(ToJava.type_to_java(rel_type), ToJava.dir_to_java(dir))
113
+ else
114
+ iter = get_relationships(ToJava.dir_to_java(dir)).iterator
115
+ if (iter.has_next)
116
+ first = iter.next
117
+ raise "Expected to only find one relationship from node #{neo_id} matching #{match.inspect}" if iter.has_next
118
+ first
119
+ end
120
+ end
121
+
122
+ between_id = match[:between] && match[:between].neo_id
123
+
124
+ if (rel && between_id)
125
+ rel.other_node(self).neo_id == between_id ? rel : nil
126
+ else
127
+ rel
128
+ end
129
+ end
130
+
131
+ def _rels(match={})
132
+ dir = match[:dir] || :both
133
+ rel_type = match[:type]
134
+
135
+ rels = if rel_type
136
+ get_relationships(ToJava.type_to_java(rel_type), ToJava.dir_to_java(dir)).iterator
137
+ else
138
+ get_relationships(ToJava.dir_to_java(dir)).iterator
139
+ end
140
+
141
+ between_id = match[:between] && match[:between].neo_id
142
+
143
+ if (between_id)
144
+ rels.find_all{|r| r.end_node.neo_id == between_id || r.start_node.neo_id == between_id}
145
+ else
146
+ rels
147
+ end
148
+
149
+ end
150
+
151
+ def class
152
+ Neo4j::Node
153
+ end
154
+ #include Neo4j::Core::Label
155
+ include Neo4j::Wrapper
156
+ end
157
+ end
158
+ end
159
+
160
+ extend_java_class(Java::OrgNeo4jKernelImplCore::NodeProxy)
161
+ end
162
+
163
+ end
@@ -0,0 +1,44 @@
1
+ module Neo4j::Embedded
2
+ class EmbeddedRelationship
3
+ class << self
4
+ # This method is used to extend a Java Neo4j class so that it includes the same mixins as this class.
5
+ def extend_java_class(java_clazz)
6
+ java_clazz.class_eval do
7
+ include Neo4j::Embedded::Property
8
+ include Neo4j::EntityEquality
9
+ extend Neo4j::Core::TxMethods
10
+
11
+ alias_method :other_node, :getOtherNode
12
+
13
+ def exist?
14
+ !!graph_database.get_relationship_by_id(neo_id)
15
+ rescue Java::OrgNeo4jGraphdb.NotFoundException
16
+ nil
17
+ end
18
+ tx_methods :exist?
19
+
20
+ def start_node
21
+ getStartNode
22
+ end
23
+ tx_methods :start_node
24
+
25
+ def del
26
+ delete
27
+ end
28
+ tx_methods :del
29
+
30
+ def end_node
31
+ getEndNode
32
+ end
33
+ tx_methods :end_node
34
+
35
+ end
36
+ end
37
+ end
38
+
39
+ extend_java_class(Java::OrgNeo4jKernelImplCore::RelationshipProxy)
40
+
41
+ end
42
+
43
+
44
+ end
@@ -0,0 +1,151 @@
1
+ # Plugin
2
+
3
+ Neo4j::Session.register_db(:embedded_db) do |*args|
4
+ Neo4j::Embedded::EmbeddedSession.new(*args)
5
+ end
6
+
7
+ Neo4j::Session.register_db(:impermanent_db) do |*args|
8
+ Neo4j::Embedded::EmbeddedImpermanentSession.new(*args)
9
+ end
10
+
11
+ module Neo4j::Embedded
12
+ class EmbeddedSession < Neo4j::Session
13
+
14
+ class Error < StandardError
15
+ end
16
+
17
+ attr_reader :graph_db, :db_location
18
+ extend Forwardable
19
+ extend Neo4j::Core::TxMethods
20
+ def_delegator :@graph_db, :begin_tx
21
+
22
+
23
+ def initialize(db_location, config={})
24
+ @db_location = db_location
25
+ @auto_commit = !!config[:auto_commit]
26
+ Neo4j::Session.register(self)
27
+ end
28
+
29
+ def start
30
+ raise Error.new("Embedded Neo4j db is already running") if running?
31
+ puts "Start embedded Neo4j db at #{db_location}"
32
+ factory = Java::OrgNeo4jGraphdbFactory::GraphDatabaseFactory.new
33
+ @graph_db = factory.newEmbeddedDatabase(db_location)
34
+ end
35
+
36
+ def factory_class
37
+ Java::OrgNeo4jGraphdbFactory::GraphDatabaseFactory
38
+ Java::OrgNeo4jTest::ImpermanentGraphDatabase
39
+ end
40
+
41
+ def close
42
+ super
43
+ shutdown
44
+ end
45
+
46
+ def shutdown
47
+ graph_db && graph_db.shutdown
48
+ @graph_db = nil
49
+ end
50
+
51
+ def running?
52
+ !!graph_db
53
+ end
54
+
55
+ def create_label(name)
56
+ EmbeddedLabel.new(self, name)
57
+ end
58
+
59
+ def load_node(neo_id)
60
+ _load_node(neo_id)
61
+ end
62
+ tx_methods :load_node
63
+
64
+ # Same as load but does not return the node as a wrapped Ruby object.
65
+ #
66
+ def _load_node(neo_id)
67
+ return nil if neo_id.nil?
68
+ @graph_db.get_node_by_id(neo_id.to_i)
69
+ rescue Java::OrgNeo4jGraphdb.NotFoundException
70
+ nil
71
+ end
72
+
73
+ def load_relationship(neo_id)
74
+ _load_relationship(neo_id)
75
+ end
76
+ tx_methods :load_relationship
77
+
78
+ def _load_relationship(neo_id)
79
+ return nil if neo_id.nil?
80
+ @graph_db.get_relationship_by_id(neo_id.to_i)
81
+ rescue Java::OrgNeo4jGraphdb.NotFoundException
82
+ nil
83
+ end
84
+
85
+ def query(*params, &query_dsl)
86
+ begin
87
+ result = super
88
+ raise CypherError.new(result.error_msg, result.error_code, result.error_status) if result.respond_to?(:error?) && result.error?
89
+ # TODO ugly, the server database must convert the result
90
+ result.respond_to?(:to_hash_enumeration) ? result.to_hash_enumeration : result.to_a
91
+ rescue Exception => e
92
+ raise CypherError.new(e,nil,nil)
93
+ end
94
+ end
95
+
96
+ def find_all_nodes(label)
97
+ EmbeddedLabel.new(self, label).find_nodes
98
+ end
99
+
100
+ def find_nodes(label, key, value)
101
+ EmbeddedLabel.new(self, label).find_nodes(key,value)
102
+ end
103
+
104
+ # Performs a cypher query with given string.
105
+ # Remember that you should close the resource iterator.
106
+ # @param [String] q the cypher query as a String
107
+ # @return (see #query)
108
+ def _query(q, params={})
109
+ engine = Java::OrgNeo4jCypherJavacompat::ExecutionEngine.new(@graph_db)
110
+ result = engine.execute(q, Neo4j::Core::HashWithIndifferentAccess.new(params))
111
+ Neo4j::Cypher::ResultWrapper.new(result)
112
+ end
113
+
114
+ def query_default_return
115
+ " RETURN n"
116
+ end
117
+
118
+ def _query_or_fail(q)
119
+ engine = Java::OrgNeo4jCypherJavacompat::ExecutionEngine.new(@graph_db)
120
+ engine.execute(q)
121
+ end
122
+
123
+ def search_result_to_enumerable(result)
124
+ result.map {|column| column['n']}
125
+ end
126
+
127
+ def create_node(properties = nil, labels=[])
128
+ if labels.empty?
129
+ _java_node = graph_db.create_node
130
+ else
131
+ labels = EmbeddedLabel.as_java(labels)
132
+ _java_node = graph_db.create_node(labels)
133
+ end
134
+ properties.each_pair { |k, v| _java_node[k]=v } if properties
135
+ _java_node
136
+ end
137
+ tx_methods :create_node
138
+
139
+ end
140
+
141
+ class EmbeddedImpermanentSession < EmbeddedSession
142
+ def start
143
+ raise Error.new("Embedded Neo4j db is already running") if running?
144
+ #puts "Start test impermanent embedded Neo4j db at #{db_location}"
145
+ @graph_db = Java::OrgNeo4jTest::TestGraphDatabaseFactory.new.newImpermanentDatabase()
146
+ end
147
+ end
148
+
149
+
150
+
151
+ end