neon 0.1.0

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.
@@ -0,0 +1,38 @@
1
+ module Neon
2
+ module Relationship
3
+ class << self
4
+ # Creates a new Relationship and immediately persists it to the database. All subsequent changes are immediately persisted.
5
+ #
6
+ # @param start_node [Node] The node from which the relationship starts i.e. is outgoing.
7
+ # @param end_node [Node] The node at which the relationship ends i.e. is incoming.
8
+ # @param attributes [Hash] An optional hash of properties to initialize the relationship with.
9
+ #
10
+ # @return [Relationship] A new relationship.
11
+ #
12
+ def new(start_node, name, end_node, attributes = {})
13
+ start_node.create_rel_to(end_node, name, attributes)
14
+ end
15
+
16
+ # Loads an existing relationship with the given id
17
+ #
18
+ # @param id [Integer] The id of the relationship to be loaded and returned.
19
+ # @param session [Session] An optional session from where to load the node.
20
+ #
21
+ # @return [Relationship] An existing relationship with the given id and specified session.
22
+ # It returns nil if the node is not found.
23
+ #
24
+ def load(id, session = Session.current)
25
+ begin
26
+ session.load_rel(id)
27
+ rescue NoMethodError
28
+ _raise_invalid_session_error(session)
29
+ end
30
+ end
31
+
32
+ private
33
+ def _raise_invalid_session_error(session)
34
+ raise Session::InvalidSessionTypeError.new(session.class)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,59 @@
1
+ # Extend the Java RelationshipProxy
2
+ Java::OrgNeo4jKernelImplCore::RelationshipProxy.class_eval do
3
+ include Neon::PropertyContainer::Embedded
4
+ include Neon::TransactionHelpers
5
+
6
+ def type
7
+ run_in_transaction { _type }
8
+ end
9
+
10
+ def start
11
+ run_in_transaction { _start }
12
+ end
13
+
14
+ def end
15
+ run_in_transaction { _end }
16
+ end
17
+
18
+ def to_s
19
+ "Embedded Relationship[#{getId}]"
20
+ end
21
+
22
+ def other_node(node)
23
+ run_in_transaction { _other_node node }
24
+ end
25
+
26
+ def nodes
27
+ run_in_transaction { get_nodes }
28
+ end
29
+
30
+ private
31
+ def _destroy
32
+ nodes = get_nodes
33
+ delete
34
+ nodes.each { |node| node.delete }
35
+ end
36
+
37
+ def _type
38
+ get_type.name
39
+ end
40
+
41
+ def _start
42
+ get_start_node
43
+ end
44
+
45
+ def _end
46
+ get_end_node
47
+ end
48
+
49
+ def _other_node(node)
50
+ case node
51
+ when start
52
+ self.end
53
+ when self.end
54
+ start
55
+ else
56
+ nil
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,73 @@
1
+ require "neon/property_container"
2
+
3
+ module Neon
4
+ module Relationship
5
+ class Rest
6
+ include PropertyContainer::Rest
7
+ attr_reader :session, :id, :start, :end, :nodes, :type
8
+
9
+ def initialize(relationship, session)
10
+ @relationship = relationship
11
+ @session = session
12
+ @id = @relationship["self"].split('/').last.to_i # Set the id
13
+ @start = @session.load(@relationship["start"])
14
+ @end = @session.load(@relationship["end"])
15
+ @nodes = [@start, @end]
16
+ @type = @relationship["type"]
17
+ end
18
+
19
+ def other_node(node)
20
+ case node
21
+ when @start
22
+ @end
23
+ when @end
24
+ @start
25
+ else
26
+ nil
27
+ end
28
+ rescue NoMethodError => e
29
+ _raise_doesnt_exist_anymore_error(e)
30
+ end
31
+
32
+
33
+ def to_s
34
+ "REST Relationship[#{@id}]"
35
+ end
36
+
37
+ def type
38
+ @relationship["type"]
39
+ end
40
+
41
+ private
42
+ def _get_properties(*keys)
43
+ @session.neo.get_relationship_properties(@relationship, *keys)
44
+ end
45
+
46
+ def _set_properties(keys)
47
+ @session.neo.set_relationship_properties(@relationship, keys)
48
+ end
49
+
50
+ def _reset_properties(attributes)
51
+ @session.neo.reset_relationship_properties(@relationship, attributes)
52
+ end
53
+
54
+ def _remove_properties(keys_to_delete)
55
+ @session.neo.remove_relationship_properties(@relationship, keys_to_delete)
56
+ end
57
+
58
+ def _set_private_vars_to_nil
59
+ @relationship = @session = @start = @end = @nodes = nil
60
+ end
61
+
62
+ def _delete
63
+ @session.neo.delete_relationship(@relationship)
64
+ end
65
+
66
+ def _destroy
67
+ _delete
68
+ @start.del
69
+ @end.del
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,68 @@
1
+ require "neon/session/rest"
2
+ require "neon/session/embedded"
3
+ require "neon/session/invalid_session"
4
+
5
+ module Neon
6
+ # A session established with a Neo4J database.
7
+ module Session
8
+ class << self
9
+ attr_accessor :current # The current default session running right now.
10
+
11
+ # Create a new session with the database.
12
+ #
13
+ # @param type [:rest, :embedded] the type of session to create. Any other type will raise a InvalidSesionTypeError.
14
+ # @param args [Array] other args to pass to the session - usually stuff like the address of the database.
15
+ #
16
+ # @return [Session] a new session of type *type* and to the database initiated with *args*.
17
+ def new(type, *args)
18
+ session = case type
19
+ when :rest
20
+ Rest.new(*args)
21
+ when :embedded
22
+ Embedded.new(*args)
23
+ else
24
+ raise InvalidSessionTypeError.new(type)
25
+ end
26
+ # Set the current session unless one already exists
27
+ @current = session unless @current
28
+ session
29
+ end
30
+
31
+ # @return [Class] the class of the current session.
32
+ def class
33
+ @current.class
34
+ end
35
+
36
+ # @return [Boolean] wether the current session is running or not.
37
+ def running?
38
+ if @current
39
+ @current.running?
40
+ else
41
+ false
42
+ end
43
+ end
44
+
45
+ # Starts the current session.
46
+ # @return [Boolean] wether the session started successfully or not.
47
+ def start
48
+ if @current
49
+ @current.start
50
+ else
51
+ false
52
+ end
53
+ end
54
+
55
+ # Stops the current session
56
+ # @return [Boolean] wether the session stopped successfully or not.
57
+ def stop
58
+ if @current
59
+ result = @current.stop
60
+ @current = nil if result
61
+ result
62
+ else
63
+ true
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,92 @@
1
+ module Neon
2
+ module Session
3
+ # A session to an embedded instance of Neo4J
4
+ class Embedded
5
+ include TransactionHelpers
6
+ # @!attribute
7
+ # @return [Boolean] Auto Transaction flag. Enabled by default.
8
+ attr_accessor :auto_tx
9
+
10
+ # Create a new session to an embedded database.
11
+ #
12
+ # @param path [String] a path to the location of the embedded database.
13
+ # @param auto_tx [Boolean] an optional flag to set auto transaction (defaults to true).
14
+ #
15
+ # @return [Embedded] a new embedded session.
16
+ def initialize(path = "neo4j", auto_tx = true)
17
+ raise "Cannot start a embedded session without JRuby" if RUBY_PLATFORM != 'java'
18
+ @db_location = path
19
+ @running = false
20
+ @auto_tx = auto_tx
21
+ end
22
+
23
+ # @return [Boolean] wether the session is running or not.
24
+ def running?
25
+ @running
26
+ end
27
+
28
+ # @return [Java::OrgNeo4jKernel::EmbeddedGraphDatabase] the Java graph database backing this session.
29
+ def database
30
+ @db
31
+ end
32
+
33
+ # @return [Boolean] wether the session started successfully.
34
+ def start
35
+ return false if @started
36
+ @started = true
37
+ @db = Java::OrgNeo4jGraphdbFactory::GraphDatabaseFactory.new.new_embedded_database(@db_location)
38
+ @running = true
39
+ end
40
+
41
+ # @return [Boolean] wether the session stopped successfully.
42
+ def stop
43
+ return false if @stopped
44
+ @db.shutdown
45
+ @running = false
46
+ @stopped = true
47
+ end
48
+
49
+ def begin_tx
50
+ @db.begin_tx
51
+ end
52
+
53
+ def run_tx(&block)
54
+ Transaction::Placebo.run(begin_tx, &block)
55
+ end
56
+
57
+ # Nodes
58
+ # Create a new node. If auto_tx is true then we begin a new transaction and commit it after the creation
59
+ def create_node(attributes, labels)
60
+ run_in_transaction { _create_node attributes, labels }
61
+ end
62
+
63
+ def load(id)
64
+ run_in_transaction { _load id }
65
+ end
66
+
67
+ def load_rel(id)
68
+ run_in_transaction { _load_rel id }
69
+ end
70
+
71
+ def to_s
72
+ @db_location
73
+ end
74
+
75
+ private
76
+ def _create_node(attributes, labels)
77
+ labels.map! { |label| Java::OrgNeo4jGraphdb::DynamicLabel.label(label) }
78
+ node = @db.create_node(*labels)
79
+ node.props = attributes
80
+ node
81
+ end
82
+
83
+ def _load(id)
84
+ @db.get_node_by_id(id)
85
+ end
86
+
87
+ def _load_rel(id)
88
+ @db.get_relationship_by_id(id)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,6 @@
1
+ module Neon
2
+ module Session
3
+ class InvalidSessionTypeError < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,53 @@
1
+ require "neography"
2
+
3
+ module Neon
4
+ module Session
5
+ class Rest
6
+ attr_reader :neo, :url
7
+ attr_accessor :auto_tx
8
+
9
+ def initialize(url = "http://localhost:7474", auto_tx = false)
10
+ @neo = Neography::Rest.new url
11
+ @url = url
12
+ @auto_tx = auto_tx
13
+ end
14
+
15
+ # These methods make no sense for a rest server so we just return true to make our specs happy
16
+ def start
17
+ true
18
+ end
19
+
20
+ alias :stop :start
21
+ alias :running? :start
22
+
23
+ def create_node(attributes, labels)
24
+ node = @neo.create_node(attributes)
25
+ return nil if node.nil?
26
+ @neo.add_label(node, labels)
27
+ Neon::Node::Rest.new(node, self)
28
+ end
29
+
30
+ def load(id)
31
+ node = @neo.get_node(id)
32
+ Neon::Node::Rest.new(node, self)
33
+ end
34
+
35
+ def load_rel(id)
36
+ rel = @neo.get_relationship(id)
37
+ Relationship::Rest.new(rel, self)
38
+ end
39
+
40
+ def begin_tx
41
+ Transaction::Rest.begin_tx(self)
42
+ end
43
+
44
+ def run_tx(&block)
45
+ Transaction::Placebo.run(begin_tx, &block)
46
+ end
47
+
48
+ def to_s
49
+ @url
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,28 @@
1
+ module Neon
2
+ module Transaction
3
+ class << self
4
+ # Begins a transaction
5
+ #
6
+ # @param session [Session::Rest, Session::Embedded] the current running session
7
+ #
8
+ # @return [Transaction::Rest, Java::OrgNeo4jKernel::PlaceboTransaction] a new transaction if one is not currently running.
9
+ # Otherwise it returns the currently running transaction.
10
+ def begin(session = Session.current)
11
+ session.begin_tx
12
+ rescue NoMethodError => e
13
+ _raise_invalid_session_error(session, e)
14
+ end
15
+
16
+ def run(session = Session.current, &block)
17
+ session.run_tx(&block)
18
+ rescue NoMethodError => e
19
+ _raise_invalid_session_error(session, e)
20
+ end
21
+
22
+ private
23
+ def _raise_invalid_session_error(session, e)
24
+ raise Neon::Session::InvalidSessionTypeError.new(session.class), e.to_s
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ module Neon
2
+ module Transaction
3
+ class Placebo
4
+ def success
5
+ @success = true
6
+ end
7
+
8
+ def failure
9
+ @success = false
10
+ end
11
+
12
+ def close
13
+ end
14
+
15
+ def success?
16
+ @success
17
+ end
18
+
19
+ def self.run(tx)
20
+ placebo = new
21
+ placebo.success # Mark for success by default
22
+ result = yield(placebo) if block_given?
23
+ if placebo.success?
24
+ tx.success
25
+ else
26
+ tx.failure
27
+ end
28
+ tx.close
29
+ return result, placebo.success?
30
+ rescue Exception => e
31
+ # Roll back the transaction
32
+ tx.failure
33
+ tx.close
34
+ raise e # Let the exception bubble up
35
+ end
36
+ end
37
+ end
38
+ end