Class: Neo4j::Server::CypherNode

Inherits:
Node
  • Object
show all
Includes:
Core::ActiveEntity, Resource
Defined in:
lib/neo4j-server/cypher_node.rb

Constant Summary collapse

MARSHAL_INSTANCE_VARIABLES =
%i[@props @labels @neo_id]

Constants included from PropertyValidator

PropertyValidator::VALID_PROPERTY_VALUE_CLASSES

Instance Attribute Summary collapse

Attributes included from Resource

#resource_data, #resource_url

Instance Method Summary collapse

Methods included from Core::ActiveEntity

#persisted?

Methods included from Resource

#convert_from_json_value, #expect_response_code!, #handle_response_error!, #init_resource_data, #resource_headers, #resource_url_id, #response_exception, #wrap_resource

Methods inherited from Node

_load, #_rel, create, find_nodes, load, validate_match!

Methods included from EntityMarshal

#marshal_dump, #marshal_load

Methods included from PropertyContainer

#[], #[]=

Methods included from PropertyValidator

#valid_property?, #validate_property!

Methods included from Node::Wrapper

#neo4j_obj, #wrapper

Methods included from EntityEquality

#==

Constructor Details

#initialize(session, value) ⇒ CypherNode

Returns a new instance of CypherNode.



9
10
11
12
13
14
15
16
17
18
19
# File 'lib/neo4j-server/cypher_node.rb', line 9

def initialize(session, value)
  @session = session

  @neo_id = if value.is_a?(Hash)
              @props = value[:data]
              @labels = value[:metadata][:labels].map!(&:to_sym) if value[:metadata]
              value[:id]
            else
              value
            end
end

Instance Attribute Details

#neo_idObject (readonly)

Returns the value of attribute neo_id.



21
22
23
# File 'lib/neo4j-server/cypher_node.rb', line 21

def neo_id
  @neo_id
end

Instance Method Details

#_cypher_label_list(labels_list) ⇒ Object



102
103
104
# File 'lib/neo4j-server/cypher_node.rb', line 102

def _cypher_label_list(labels_list)
  ':' + labels_list.map { |label| "`#{label}`" }.join(':')
end

#_java_nodeObject

TODO, needed by neo4j-cypher



28
29
30
# File 'lib/neo4j-server/cypher_node.rb', line 28

def _java_node
  self
end

#_set_label_query(labels_to_add, labels_to_remove) ⇒ Object



128
129
130
131
132
133
# File 'lib/neo4j-server/cypher_node.rb', line 128

def _set_label_query(labels_to_add, labels_to_remove)
  query = match_start_query
  query = query.remove(n: labels_to_remove) unless labels_to_remove.empty?
  query = query.set(n: labels_to_add) unless labels_to_add.empty?
  query
end

#add_label(*new_labels) ⇒ Object



106
107
108
109
# File 'lib/neo4j-server/cypher_node.rb', line 106

def add_label(*new_labels)
  @session._query_or_fail(match_start_query.set(n: new_labels), false)
  new_labels.each { |label| labels << label }
end

#create_rel(type, other_node, props = nil) ⇒ Object

Creates a relationship of given type to other_node with optionally properties

Parameters:

  • type (Symbol)

    the type of the relation between the two nodes

  • other_node (Neo4j::Node)

    the other node

  • props (Hash<Symbol, Object>) (defaults to: nil)

    optionally properties for the created relationship



33
34
35
36
37
38
39
40
# File 'lib/neo4j-server/cypher_node.rb', line 33

def create_rel(type, other_node, props = nil)
  q = @session.query.match(:a, :b).where(a: {neo_id: neo_id}, b: {neo_id: other_node.neo_id})
              .create("(a)-[r:`#{type}`]->(b)").break.set(r: props).return(r: :neo_id)

  id = @session._query_or_fail(q, true)

  CypherRelationship.new(@session, type: type, data: props, start: neo_id, end: other_node.neo_id, id: id)
end

#delObject Also known as: delete, destroy

Deletes this node from the database



136
137
138
139
# File 'lib/neo4j-server/cypher_node.rb', line 136

def del
  query = match_start_query.optional_match('(n)-[r]-()').delete(:n, :r)
  @session._query_or_fail(query, false)
end

#exist?Boolean

Returns true if the node exists in the database.

Returns:

  • (Boolean)

    true if the node exists in the database



145
146
147
# File 'lib/neo4j-server/cypher_node.rb', line 145

def exist?
  !@session._query(match_start_query.return(n: :neo_id)).data.empty?
end

#get_property(key) ⇒ Object

Directly get the property on the node (low level method, may need transaction)

Parameters:

  • key (Symbol, String)

Returns:

  • the value of the key



93
94
95
# File 'lib/neo4j-server/cypher_node.rb', line 93

def get_property(key)
  @props ? @props[key.to_sym] : @session._query_or_fail(match_start_query.return(n: key), true)
end

#inspectObject



23
24
25
# File 'lib/neo4j-server/cypher_node.rb', line 23

def inspect
  "CypherNode #{neo_id} (#{object_id})"
end

#labelsArray<Symbol>

Returns all labels on the node.

Returns:

  • (Array<Symbol>)

    all labels on the node



98
99
100
# File 'lib/neo4j-server/cypher_node.rb', line 98

def labels
  @labels ||= @session._query_or_fail(match_start_query.return('labels(n) AS labels'), true).map(&:to_sym)
end

#match(clazz, returns, match = {}) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/neo4j-server/cypher_node.rb', line 176

def match(clazz, returns, match = {})
  ::Neo4j::Node.validate_match!(match)

  query = self.query

  query = query.match(:p).where(p: {neo_id: match[:between].neo_id}) if match[:between]

  r = query.match("(n)#{relationship_arrow(match)}(p)").return(returns).response

  r.raise_error if r.error?

  r.to_node_enumeration.map(&:result)
end

#node(match = {}) ⇒ Object

Returns the only node of a given type and direction that is attached to this node, or nil. This is a convenience method that is used in the commonly occuring situation where a node has exactly zero or one relationships of a given type and direction to another node. Typically this invariant is maintained by the rest of the code: if at any time more than one such relationships exist, it is a fatal error that should generate an exception.

This method reflects that semantics and returns either:

  • nil if there are zero relationships of the given type and direction,

  • the relationship if there’s exactly one, or

  • throws an exception in all other cases.

This method should be used only in situations with an invariant as described above. In those situations, a “state-checking” method (e.g. #rel?) is not required, because this method behaves correctly “out of the box.”



150
151
152
# File 'lib/neo4j-server/cypher_node.rb', line 150

def node(match = {})
  ensure_single_relationship { match(CypherNode, 'p as result LIMIT 2', match) }
end

#nodes(match = {}) ⇒ Enumerable<Neo4j::Node>

This method is abstract.
Note:

it’s possible that the same node is returned more than once because of several relationship reaching to the same node, see #outgoing for alternative

Works like #rels method but instead returns the nodes. It does try to load a Ruby wrapper around each node

Parameters:

  • match (Hash) (defaults to: {})

    the options to create a message with.

Returns:

  • (Enumerable<Neo4j::Node>)

    an Enumeration of either Neo4j::Node objects or wrapped Neo4j::Node objects



166
167
168
# File 'lib/neo4j-server/cypher_node.rb', line 166

def nodes(match = {})
  match(CypherNode, 'p as result', match)
end

#propsHash<Symbol, Object>

Returns all properties of the node.

Returns:

  • (Hash<Symbol, Object>)

    all properties of the node



43
44
45
46
47
48
49
50
# File 'lib/neo4j-server/cypher_node.rb', line 43

def props
  if @props
    @props
  else
    hash = @session._query_entity_data(match_start_query.return(:n), nil)
    @props = Hash[hash[:data].to_a]
  end
end

#props=(properties) ⇒ Object

replace all properties with new properties

Parameters:

  • properties (Hash<Symbol, Object>)

    a hash of properties the node should have



69
70
71
72
73
# File 'lib/neo4j-server/cypher_node.rb', line 69

def props=(properties)
  refresh
  @session._query_or_fail(match_start_query.set_props(n: properties), false)
  properties
end

#query(identifier = :n) ⇒ Object



190
191
192
# File 'lib/neo4j-server/cypher_node.rb', line 190

def query(identifier = :n)
  @session.query.match(identifier).where(identifier => {neo_id: neo_id})
end

#refreshObject



52
53
54
# File 'lib/neo4j-server/cypher_node.rb', line 52

def refresh
  @props = nil
end

#rel(match = {}) ⇒ Object

Same as #node but returns the relationship. Notice it may raise an exception if there are more then one relationship matching.



155
156
157
# File 'lib/neo4j-server/cypher_node.rb', line 155

def rel(match = {})
  ensure_single_relationship { match(CypherRelationship, 'r as result LIMIT 2', match) }
end

#rel?(match = {}) ⇒ Boolean

Returns true or false if there is one or more relationships

Returns:

  • (Boolean)


160
161
162
163
# File 'lib/neo4j-server/cypher_node.rb', line 160

def rel?(match = {})
  result = match(CypherRelationship, 'r as result', match)
  !!result.first
end

#rels(match = {dir: :both}) ⇒ Enumerable<Neo4j::Relationship>

Returns an enumeration of relationships. It always returns relationships of depth one.

Examples:

Return both incoming and outgoing relationships of any type

node_a.rels

All outgoing or incoming relationship of type friends

node_a.rels(type: :friends)

All outgoing relationships between me and another node of type friends

node_a.rels(type: :friends, dir: :outgoing, between: node_b)

Parameters:

  • match (Hash) (defaults to: {dir: :both})

    the options to create a message with.

Options Hash (match):

  • :dir (Symbol)

    dir the direction of the relationship, allowed values: :both, :incoming, :outgoing.

  • :type (Symbol)

    the type of relationship to navigate

  • :between (Symbol)

    return all the relationships between this and given node

Returns:



171
172
173
# File 'lib/neo4j-server/cypher_node.rb', line 171

def rels(match = {dir: :both})
  match(CypherRelationship, 'r as result', match)
end

#remove_label(*target_labels) ⇒ Object



111
112
113
114
# File 'lib/neo4j-server/cypher_node.rb', line 111

def remove_label(*target_labels)
  @session._query_or_fail(match_start_query.remove(n: target_labels), false)
  target_labels.each { |label| labels.delete(label) } unless labels.nil?
end

#remove_properties(properties) ⇒ Object



75
76
77
78
79
80
# File 'lib/neo4j-server/cypher_node.rb', line 75

def remove_properties(properties)
  return if properties.empty?

  refresh
  @session._query_or_fail(match_start_query.remove(n: properties), false, neo_id: neo_id)
end

#remove_property(key) ⇒ Object

Directly remove the property on the node (low level method, may need transaction)



57
58
59
60
# File 'lib/neo4j-server/cypher_node.rb', line 57

def remove_property(key)
  refresh
  @session._query_or_fail(match_start_query.remove(n: key), false)
end

#set_label(*label_names) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/neo4j-server/cypher_node.rb', line 116

def set_label(*label_names)
  labels_to_add = label_names.map(&:to_sym).uniq
  labels_to_remove = labels - label_names

  common_labels = labels & labels_to_add
  labels_to_add -= common_labels
  labels_to_remove -= common_labels

  query = _set_label_query(labels_to_add, labels_to_remove)
  @session._query_or_fail(query, false) unless (labels_to_add + labels_to_remove).empty?
end

#set_property(key, value) ⇒ Object

Directly set the property on the node (low level method, may need transaction)

Parameters:

  • key (Symbol, String)
  • value

    see Neo4j::PropertyValidator::VALID_PROPERTY_VALUE_CLASSES for valid values



63
64
65
66
# File 'lib/neo4j-server/cypher_node.rb', line 63

def set_property(key, value)
  refresh
  @session._query_or_fail(match_start_query.set(n: {key => value}), false)
end

#update_props(properties) ⇒ Object

Updates the properties, keeps old properties

Parameters:

  • properties (Hash<Symbol, Object>)

    hash of properties that should be updated on the node



83
84
85
86
87
88
89
90
# File 'lib/neo4j-server/cypher_node.rb', line 83

def update_props(properties)
  refresh
  return if properties.empty?

  @session._query_or_fail(match_start_query.set(n: properties), false)

  properties
end