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,22 @@
1
+ module Neo4j
2
+ module PropertyContainer
3
+ include Neo4j::PropertyValidator
4
+
5
+ # Returns the Neo4j Property of given key
6
+ def [](key)
7
+ get_property(key)
8
+ end
9
+
10
+
11
+ # Sets the neo4j property
12
+ def []=(key,value)
13
+ validate_property(value)
14
+
15
+ if value.nil?
16
+ remove_property(key)
17
+ else
18
+ set_property(key,value)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module Neo4j
2
+ module PropertyValidator
3
+
4
+ class InvalidPropertyException < Exception
5
+
6
+ end
7
+
8
+ # the valid values on a property, and arrays of those.
9
+ VALID_PROPERTY_VALUE_CLASSES = Set.new([Array, NilClass, String, Float, TrueClass, FalseClass, Fixnum])
10
+
11
+ # @param [Object] value the value we want to check if it's a valid neo4j property value
12
+ # @return [True, False] A false means it can't be persisted.
13
+ def valid_property?(value)
14
+ VALID_PROPERTY_VALUE_CLASSES.include?(value.class)
15
+ end
16
+
17
+ def validate_property(value)
18
+ unless valid_property?(value)
19
+ raise Neo4j::PropertyValidator::InvalidPropertyException.new("Not valid Neo4j Property value #{value.class}, valid: #{Neo4j::Node::VALID_PROPERTY_VALUE_CLASSES.to_a.join(', ')}")
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,84 @@
1
+ module Neo4j
2
+ # A relationship between two nodes in the graph. A relationship has a start node, an end node and a type.
3
+ # You can attach properties to relationships like Neo4j::Node.
4
+ #
5
+ # The fact that the relationship API gives meaning to start and end nodes implicitly means that all relationships have a direction.
6
+ # In the example above, rel would be directed from node to otherNode.
7
+ # A relationship's start node and end node and their relation to outgoing and incoming are defined so that the assertions in the following code are true:
8
+ #
9
+ # Furthermore, Neo4j guarantees that a relationship is never "hanging freely,"
10
+ # i.e. start_node, end_node and other_node are guaranteed to always return valid, non-nil nodes.
11
+ class Relationship
12
+
13
+ include PropertyContainer
14
+ include EntityEquality
15
+
16
+ # @abstract
17
+ def start_node
18
+ raise 'not implemented'
19
+ end
20
+
21
+ # @abstract
22
+ def end_node
23
+ raise 'not implemented'
24
+ end
25
+
26
+ # @abstract
27
+ def del
28
+ raise 'not implemented'
29
+ end
30
+
31
+ # The unique neo4j id
32
+ # @abstract
33
+ def neo_id
34
+ raise 'not implemented'
35
+ end
36
+
37
+ # @return [true, false] if the relationship exists
38
+ # @abstract
39
+ def exist?
40
+ raise 'not implemented'
41
+ end
42
+
43
+ # Returns the relationship name
44
+ #
45
+ # @example
46
+ # a = Neo4j::Node.new
47
+ # a.create_rel(:friends, node_b)
48
+ # a.rels.first.rel_type # => :friends
49
+ # @return [Symbol] the type of the relationship
50
+ def rel_type
51
+ raise 'not implemented'
52
+ end
53
+
54
+ # A convenience operation that, given a node that is attached to this relationship, returns the other node.
55
+ # For example if node is a start node, the end node will be returned, and vice versa.
56
+ # This is a very convenient operation when you're manually traversing the node space by invoking one of the #rels
57
+ # method on a node. For example, to get the node "at the other end" of a relationship, use the following:
58
+ #
59
+ # @example
60
+ # end_node = node.rels.first.other_node(node)
61
+ #
62
+ # @raise This operation will throw a runtime exception if node is neither this relationship's start node nor its end node.
63
+ #
64
+ # @param [Neo4j::Node] node the node that we don't want to return
65
+ # @return [Neo4j::Node] the other node wrapper
66
+ # @see #_other_node
67
+ def other_node(node)
68
+ if node == start_node
69
+ return end_node
70
+ elsif node == end_node
71
+ return start_node
72
+ else
73
+ raise "Node #{node.inspect} is neither start nor end node"
74
+ end
75
+ end
76
+
77
+ class << self
78
+ def load(neo_id, session = Neo4j::Session.current)
79
+ session.load_relationship(neo_id)
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,124 @@
1
+ module Neo4j
2
+ class Session
3
+
4
+ @@current_session = nil
5
+ @@factories = {}
6
+
7
+ # @abstract
8
+ def close
9
+ self.class.unregister(self)
10
+ end
11
+
12
+ # Only for embedded database
13
+ # @abstract
14
+ def start
15
+ raise "not impl."
16
+ end
17
+
18
+ # Only for embedded database
19
+ # @abstract
20
+ def shutdown
21
+ raise "not impl."
22
+ end
23
+
24
+ # Only for embedded database
25
+ # @abstract
26
+ def running
27
+ raise "not impl."
28
+ end
29
+
30
+ def auto_commit?
31
+ true # TODO
32
+ end
33
+
34
+ # @abstract
35
+ def begin_tx
36
+ raise "not impl."
37
+ end
38
+
39
+ class CypherError < StandardError
40
+ attr_reader :error_msg, :error_status, :error_code
41
+ def initialize(error_msg, error_code, error_status)
42
+ super(error_msg)
43
+ @error_msg = error_msg
44
+ @error_status = error_status
45
+ end
46
+ end
47
+
48
+ # Executes a Cypher Query
49
+ # Returns an enumerable of hash values, column => value
50
+ #
51
+ # @example Using the Cypher DSL
52
+ # q = Neo4j.query("START n=node({param}) RETURN n", :param => 0)
53
+ # q.first[:n] #=> the node
54
+ # q.columns.first => :n
55
+ #
56
+ # @example Using the Cypher DSL
57
+ # q = Neo4j.query{ match node(3) <=> node(:x); ret :x}
58
+ # q.first[:n] #=> the @node
59
+ # q.columns.first => :n
60
+ #
61
+ # @example Using the Cypher DSL and one parameter (n=Neo4j.ref_node)
62
+ # q = Neo4j.query(Neo4j.ref_node){|n| n <=> node(:x); :x}
63
+ # q.first[:n] #=> the @node
64
+ # q.columns.first => :n
65
+ #
66
+ # @example Using an array of nodes
67
+ # # same as - two_nodes=node(Neo4j.ref_node.neo_id, node_b.neo_id), b = node(b.neo_id)
68
+ # q = Neo4j.query([Neo4j.ref_node, node_b], node_c){|two_nodes, b| two_nodes <=> b; b}
69
+ #
70
+ # @see Cypher
71
+ # @see http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html The Cypher Query Language Documentation
72
+ # @note Returns a read-once only forward iterable.
73
+ # @param params parameter for the query_dsl block
74
+ # @return [Neo4j::Cypher::ResultWrapper] a forward read once only Enumerable, containing hash values.
75
+ #
76
+ # @abstract
77
+ def query(*params, &query_dsl)
78
+ cypher_params = params.pop if params.last.is_a?(Hash)
79
+ q = query_dsl ? Neo4j::Cypher.query(*params, &query_dsl).to_s : params[0]
80
+ _query(q, cypher_params)
81
+ end
82
+
83
+ # Same as #query but does not accept an DSL and returns the raw result from the database.
84
+ # Notice, it might return different values depending on which database is used, embedded or server.
85
+ # @abstract
86
+ def _query(*params)
87
+ raise 'not implemented'
88
+ end
89
+
90
+ class << self
91
+ # Creates a new session
92
+ # @param db_type the type of database, e.g. :embedded_db, or :server_db
93
+ def open(db_type, *params)
94
+ unless (@@factories[db_type])
95
+ raise "Can't connect to database '#{db_type}', available #{@@factories.keys.join(',')}"
96
+ end
97
+ session = @@factories[db_type].call(*params)
98
+ register(session)
99
+ end
100
+
101
+ def current
102
+ @@current_session
103
+ end
104
+
105
+ def set_current(session)
106
+ @@current_session = session
107
+ end
108
+
109
+ def register(session)
110
+ set_current(session) unless @@current_session
111
+ @@current_session
112
+ end
113
+
114
+ def unregister(session)
115
+ @@current_session = nil if @@current_session == session
116
+ end
117
+
118
+ def register_db(db, &session_factory)
119
+ raise "Factory for #{db} already exists" if @@factories[db]
120
+ @@factories[db] = session_factory
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,131 @@
1
+ # borrowed from architect4r
2
+ require 'os'
3
+
4
+ namespace :neo4j do
5
+ desc "Install Neo4j"
6
+ task :install, :edition, :version do |t, args|
7
+ args.with_defaults(:edition => "community", :version => "1.7")
8
+ puts "Installing Neo4j-#{args[:edition]}-#{args[:version]}"
9
+
10
+ if OS::Underlying.windows?
11
+ # Download Neo4j
12
+ unless File.exist?('neo4j.zip')
13
+ df = File.open('neo4j.zip', 'wb')
14
+ begin
15
+ df << HTTParty.get("http://dist.neo4j.org/neo4j-#{args[:edition]}-#{args[:version]}-windows.zip")
16
+ ensure
17
+ df.close()
18
+ end
19
+ end
20
+
21
+ # Extract and move to neo4j directory
22
+ unless File.exist?('neo4j')
23
+ Zip::ZipFile.open('neo4j.zip') do |zip_file|
24
+ zip_file.each do |f|
25
+ f_path=File.join(".", f.name)
26
+ FileUtils.mkdir_p(File.dirname(f_path))
27
+ begin
28
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
29
+ rescue
30
+ puts f.name + " failed to extract."
31
+ end
32
+ end
33
+ end
34
+ FileUtils.mv "neo4j-#{args[:edition]}-#{args[:version]}", "neo4j"
35
+ end
36
+
37
+ # Install if running with Admin Privileges
38
+ if %x[reg query "HKU\\S-1-5-19"].size > 0
39
+ %x[neo4j/bin/neo4j install]
40
+ puts "Neo4j Installed as a service."
41
+ end
42
+
43
+ else
44
+ %x[wget http://dist.neo4j.org/neo4j-#{args[:edition]}-#{args[:version]}-unix.tar.gz]
45
+ %x[tar -xvzf neo4j-#{args[:edition]}-#{args[:version]}-unix.tar.gz]
46
+ %x[mv neo4j-#{args[:edition]}-#{args[:version]} neo4j]
47
+ %x[rm neo4j-#{args[:edition]}-#{args[:version]}-unix.tar.gz]
48
+ puts "Neo4j Installed in to neo4j directory."
49
+ end
50
+ puts "Type 'rake neo4j:start' to start it"
51
+ end
52
+
53
+ desc "Start the Neo4j Server"
54
+ task :start do
55
+ puts "Starting Neo4j..."
56
+ if OS::Underlying.windows?
57
+ if %x[reg query "HKU\\S-1-5-19"].size > 0
58
+ %x[neo4j/bin/Neo4j.bat start] #start service
59
+ else
60
+ puts "Starting Neo4j directly, not as a service."
61
+ %x[neo4j/bin/Neo4j.bat]
62
+ end
63
+ else
64
+ %x[neo4j/bin/neo4j start]
65
+ end
66
+ end
67
+
68
+ desc "Stop the Neo4j Server"
69
+ task :stop do
70
+ puts "Stopping Neo4j..."
71
+ if OS::Underlying.windows?
72
+ if %x[reg query "HKU\\S-1-5-19"].size > 0
73
+ %x[neo4j/bin/Neo4j.bat stop] #stop service
74
+ else
75
+ puts "You do not have administrative rights to stop the Neo4j Service"
76
+ end
77
+ else
78
+ %x[neo4j/bin/neo4j stop]
79
+ end
80
+ end
81
+
82
+ desc "Restart the Neo4j Server"
83
+ task :restart do
84
+ puts "Restarting Neo4j..."
85
+ if OS::Underlying.windows?
86
+ if %x[reg query "HKU\\S-1-5-19"].size > 0
87
+ %x[neo4j/bin/Neo4j.bat restart]
88
+ else
89
+ puts "You do not have administrative rights to restart the Neo4j Service"
90
+ end
91
+ else
92
+ %x[neo4j/bin/neo4j restart]
93
+ end
94
+ end
95
+
96
+ desc "Reset the Neo4j Server"
97
+ task :reset_yes_i_am_sure do
98
+ # Stop the server
99
+ if OS::Underlying.windows?
100
+ if %x[reg query "HKU\\S-1-5-19"].size > 0
101
+ %x[neo4j/bin/Neo4j.bat stop]
102
+
103
+ # Reset the database
104
+ FileUtils.rm_rf("neo4j/data/graph.db")
105
+ FileUtils.mkdir("neo4j/data/graph.db")
106
+
107
+ # Remove log files
108
+ FileUtils.rm_rf("neo4j/data/log")
109
+ FileUtils.mkdir("neo4j/data/log")
110
+
111
+ %x[neo4j/bin/Neo4j.bat start]
112
+ else
113
+ puts "You do not have administrative rights to reset the Neo4j Service"
114
+ end
115
+ else
116
+ %x[neo4j/bin/neo4j stop]
117
+
118
+ # Reset the database
119
+ FileUtils.rm_rf("neo4j/data/graph.db")
120
+ FileUtils.mkdir("neo4j/data/graph.db")
121
+
122
+ # Remove log files
123
+ FileUtils.rm_rf("neo4j/data/log")
124
+ FileUtils.mkdir("neo4j/data/log")
125
+
126
+ # Start the server
127
+ %x[neo4j/bin/neo4j start]
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,52 @@
1
+ module Neo4j
2
+ class Transaction
3
+ def self.new(current = Session.current)
4
+ current.begin_tx
5
+ end
6
+
7
+
8
+ class << self
9
+
10
+ def run(run_in_tx=true)
11
+ raise ArgumentError.new("Expected a block to run in Transaction.run") unless block_given?
12
+
13
+ return yield(nil) unless run_in_tx
14
+
15
+ begin
16
+ tx = Neo4j::Transaction.new
17
+ ret = yield tx
18
+ tx.success
19
+ rescue Exception => e
20
+ if e.respond_to?(:cause) && e.cause
21
+ puts "Java Exception in a transaction, cause: #{e.cause}"
22
+ e.cause.print_stack_trace
23
+ end
24
+ tx.failure unless tx.nil?
25
+ raise
26
+ ensure
27
+ tx.finish unless tx.nil?
28
+ end
29
+ ret
30
+ end
31
+
32
+ def current
33
+ Thread.current[:neo4j_curr_tx]
34
+ end
35
+
36
+ def unregister(tx)
37
+ Thread.current[:neo4j_curr_tx] = nil if tx == Thread.current[:neo4j_curr_tx]
38
+ end
39
+
40
+ def register(tx)
41
+ # we don't support running more then one transaction per thread
42
+ raise "Already running a transaction" if current
43
+ Thread.current[:neo4j_curr_tx] = tx
44
+ end
45
+
46
+ def unregister_current
47
+ Thread.current[:neo4j_curr_tx] = nil
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,35 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'neo4j-core/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "neo4j-core"
8
+ s.version = Neo4j::Core::VERSION
9
+ s.required_ruby_version = ">= 1.8.7"
10
+
11
+ s.authors = "Andreas Ronge"
12
+ s.email = 'andreas.ronge@gmail.com'
13
+ s.homepage = "http://github.com/andreasronge/neo4j-core/tree"
14
+ s.rubyforge_project = 'neo4j-core'
15
+ s.summary = "A graph database for JRuby"
16
+ s.description = <<-EOF
17
+ You can think of Neo4j as a high-performance graph engine with all the features of a mature and robust database.
18
+ The programmer works with an object-oriented, flexible network structure rather than with strict and static tables
19
+ yet enjoys all the benefits of a fully transactional, enterprise-strength database.
20
+ It comes included with the Apache Lucene document database.
21
+ EOF
22
+
23
+ s.require_path = 'lib'
24
+ s.files = Dir.glob("{bin,lib,config}/**/*") + %w(README.md Gemfile neo4j-core.gemspec)
25
+ s.has_rdoc = true
26
+ s.extra_rdoc_files = %w( README.md )
27
+ s.rdoc_options = ["--quiet", "--title", "Neo4j::Core", "--line-numbers", "--main", "README.rdoc", "--inline-source"]
28
+
29
+ # Not released yet
30
+ s.add_dependency("httparty")
31
+ s.add_dependency("json")
32
+ s.add_dependency("neo4j-cypher")
33
+ # s.add_dependency("neo4j-community", '>=1.9.M05', '<2.0')
34
+ # s.add_dependency("neo4j-cypher", '~> 1.0.0')
35
+ end