Class: Tina4::Drivers::ArangoGraphDriver

Inherits:
GraphAdapter show all
Defined in:
lib/tina4/drivers/arango_graph_driver.rb

Defined Under Namespace

Classes: ArangoConnectError, ArangoError

Constant Summary collapse

VERTEX_COLLECTION =
"tina4_nodes"
EDGE_COLLECTION =
"tina4_edges"
TYPE_DOCUMENT =

Arango collection types: 2 = document, 3 = edge (verified live — the edge collection MUST be type 3 for AABB traversal to work).

2
TYPE_EDGE =
3
RESERVED =
%w[_id _key _rev _from _to _labels _type].freeze

Instance Method Summary collapse

Methods inherited from GraphAdapter

#get_error

Constructor Details

#initialize(graph_url, username: "", password: "") ⇒ ArangoGraphDriver

Returns a new instance of ArangoGraphDriver.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 38

def initialize(graph_url, username: "", password: "")
  @url = graph_url
  @last_error = nil
  @timeout = Tina4.resolve_graph_connect_timeout
  scheme = graph_url.use_tls ? "https" : "http"
  @base = "#{scheme}://#{graph_url.host}:#{graph_url.port}"
  @database = graph_url.graph || "_system"
  @user = graph_url.username
  @user = username unless @user && !@user.empty?
  @user = "root" if @user.nil? || @user.empty?
  @password = graph_url.password
  @password = password unless @password && !@password.empty?
  ensure_collections
end

Instance Method Details

#add_edge(from_id, to_id, type, properties = nil) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 74

def add_edge(from_id, to_id, type, properties = nil)
  doc = (properties || {}).dup
  doc["_from"] = from_id
  doc["_to"] = to_id
  doc["_type"] = type
  rows = aql("INSERT @doc INTO #{EDGE_COLLECTION} RETURN NEW", { "doc" => doc })
  return nil if rows.empty?

  row = rows[0]
  Tina4::GraphEdge.new(
    id: row["_id"], type: row["_type"], from: row["_from"], to: row["_to"],
    properties: clean_props(row)
  )
end

#add_node(label, properties = nil) ⇒ Object

-- portable node/edge/traverse core (AQL) --------------------------



67
68
69
70
71
72
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 67

def add_node(label, properties = nil)
  doc = (properties || {}).dup
  doc["_labels"] = [label]
  rows = aql("INSERT @doc INTO #{VERTEX_COLLECTION} RETURN NEW", { "doc" => doc })
  node_from_doc(rows[0])
end

#closeObject



126
127
128
129
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 126

def close
  # Net::HTTP opens a fresh connection per request here — nothing to hold open.
  true
end

#delete_node(node_id) ⇒ Object



104
105
106
107
108
109
110
111
112
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 104

def delete_node(node_id)
  # Remove the node and any edges touching it, so a re-read is a clean miss.
  aql(
    "FOR e IN #{EDGE_COLLECTION} FILTER e._from == @id OR e._to == @id " \
    "REMOVE e IN #{EDGE_COLLECTION}", { "id" => node_id }
  )
  aql("REMOVE PARSE_IDENTIFIER(@id).key IN #{VERTEX_COLLECTION}", { "id" => node_id })
  true
end

#execute(text, params = nil) ⇒ Object



61
62
63
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 61

def execute(text, params = nil)
  query(text, params)
end

#get_node(node_id) ⇒ Object



89
90
91
92
93
94
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 89

def get_node(node_id)
  rows = aql("RETURN DOCUMENT(@id)", { "id" => node_id })
  return nil if rows.empty? || rows[0].nil?

  node_from_doc(rows[0])
end

#neighbors(node_id, direction: "both", edge_type: nil, limit: 100) ⇒ Object



114
115
116
117
118
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 114

def neighbors(node_id, direction: "both", edge_type: nil, limit: 100)
  rows = aql(traversal_query(1, direction, edge_type),
             traversal_bind(node_id, limit, edge_type))
  rows.map { |doc| node_from_doc(doc) }
end

#query(text, params = nil) ⇒ Object

-- raw pass-through (native AQL) -----------------------------------



55
56
57
58
59
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 55

def query(text, params = nil)
  rows = aql(text, params)
  columns = rows[0].is_a?(Hash) ? rows[0].keys : []
  Tina4::GraphResult.new(records: rows, columns: columns)
end

#traverse(start_id, depth: 1, direction: "both", edge_type: nil, limit: 1000) ⇒ Object



120
121
122
123
124
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 120

def traverse(start_id, depth: 1, direction: "both", edge_type: nil, limit: 1000)
  rows = aql(traversal_query(depth.to_i, direction, edge_type),
             traversal_bind(start_id, limit, edge_type))
  rows.map { |doc| node_from_doc(doc) }
end

#update_node(node_id, properties) ⇒ Object



96
97
98
99
100
101
102
# File 'lib/tina4/drivers/arango_graph_driver.rb', line 96

def update_node(node_id, properties)
  rows = aql(
    "UPDATE PARSE_IDENTIFIER(@id).key WITH @props IN #{VERTEX_COLLECTION} RETURN NEW",
    { "id" => node_id, "props" => properties || {} }
  )
  node_from_doc(rows[0])
end