neo4j-core 3.0.0.alpha.1

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