Graph

The driver can execute graph queries via the CassSession function cass_session_execute_dse_graph() and the DseGraphStatement type.

The following “test” graph is created using gremlin-shell (via bin/dse gremlin-shell):

gremlin> system.graph('test').create()
==>null
gremlin> :remote config alias g test.g
==>g=test.g
gremlin> Vertex marko = graph.addVertex(label, 'person', 'name', 'marko', 'age', 29);
==>v[{~label=person, ...}]
gremlin> Vertex vadas = graph.addVertex(label, 'person', 'name', 'vadas', 'age', 27);
==>v[{~label=person, ...}]
gremlin> Vertex lop = graph.addVertex(label, 'software', 'name', 'lop', 'lang', 'java');
==>v[{~label=software, member_id=3, community_id=955191296}]
gremlin> Vertex josh = graph.addVertex(label, 'person', 'name', 'josh', 'age', 32);
==>v[{~label=person, ...}]
gremlin> Vertex ripple = graph.addVertex(label, 'software', 'name', 'ripple', 'lang', 'java');
==>v[{~label=software, ...}]
gremlin> Vertex peter = graph.addVertex(label, 'person', 'name', 'peter', 'age', 35);
==>v[{~label=person, ...}]
gremlin> marko.addEdge('knows', vadas, 'weight', 0.5f);
==>e[{out_vertex=...
gremlin> marko.addEdge('knows', josh, 'weight', 1.0f);
==>e[{out_vertex={...}, , in_vertex={...}]
gremlin> marko.addEdge('created', lop, 'weight', 0.4f);
==>e[{out_vertex={...}, , in_vertex={...}]
gremlin> josh.addEdge('created', ripple, 'weight', 1.0f);
==>e[{out_vertex={...}, , in_vertex={...}]
gremlin> josh.addEdge('created', lop, 'weight', 0.4f);
==>e[{out_vertex={...}, , in_vertex={...}]
gremlin> peter.addEdge('created', lop, 'weight', 0.2f);
==>e[{out_vertex={...}, , in_vertex={...}]

The “test” graph can then be queried using the driver:

Copy
/* Create a graph options so that we can set a specific graph name: "test" */
DseGraphOptions* options = dse_graph_options_new();

/* Set the graph name */
dse_graph_options_set_graph_name(options, "test");

/* Create a graph query */
DseGraphStatement* statement =
  dse_graph_statement_new("g.V().has('name','marko').out('knows').values('name')", options);

/* Execute the graph query */
CassFuture* future =
  cass_session_execute_dse_graph(session, statement);

/* Check and handle the result */
if (cass_future_error_code(future) == CASS_OK) {
  DseGraphResultSet* resultset = cass_future_get_dse_graph_resultset(future);

  /* Handle result set */
} else {
  /* Handle error */
}

/* Cleanup */
cass_future_free(future);
dse_graph_statement_free(statement);

Graph options

A graph name should not be set if for executing system queries. This can also be accomplished by passing NULL for the options argument to dse_graph_statement_new().

Copy
/* Create a system query (note: passing NULL for options) */
DseGraphStatement* statement =
  dse_graph_statement_new("system.graph('test').ifNotExists().create()", NULL);

/* Create and bind "name" value */
DseGraphObject* values = dse_graph_object_new();
dse_graph_object_add_string(values, "name", name);
dse_graph_object_finish(values);
dse_graph_statement_bind_values(statement, values);
dse_graph_object_free(values);

/* Execute the graph query */
CassFuture* future =
  cass_session_execute_dse_graph(session, statement);

/* Handle results... */

/* Cleanup */
cass_future_free(future);
dse_graph_statement_free(statement);

The graph options object should be created once and reused for all graph queries that use the same options.

Copy
DseGraphOptions* test_options = NULL;

int main() {
  /* Create a graph options so that we can set a specific graph name: "test" */
  test_options = dse_graph_options_new();

  /* Set the graph name */
  dse_graph_options_set_graph_name(options, "test");

  /* Run application */

  /* Free the options at the end of execution */
  dse_graph_options_free(test_options);
}

Data types

Supported data types can be found in the DSE Graph documentation. In the RC version of the driver there are some known limitations for some data types:

DSE Graph Data Type Limitations
blob Returned as a base64 string
decimal Truncated to a double precision floating point number or may not be handled
duration Returned as a string using this format: https://en.wikipedia.org/wiki/ISO_8601#Durations
inet Returned as a string
varint Truncated to a double precision floating point number, 64-bit integer, or may not be handled
linestring Returned as a string using Well-known text (https://en.wikipedia.org/wiki/Well-known_text)
point Returned as a string using Well-known text (https://en.wikipedia.org/wiki/Well-known_text)
polygon Returned as a string using Well-known text (https://en.wikipedia.org/wiki/Well-known_text)
timestamp Returned as a string using this format: https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations
uuid Returned as a string

Geometric types

Graph queries can use well-known text (https://en.wikipedia.org/wiki/Well-known_text) for handling geometric types or they can use the driver’s built-in geometric types and functions. To bind a geometric type parameter use dse_graph_object_add_point(), dse_graph_object_add_line_string() and dse_graph_object_add_polygon(). To retrieve a geometric type from a graph result use dse_graph_result_as_point(), dse_graph_result_as_line_string() and dse_graph_result_as_polygon(). See the geotypes section for more information.

Parameter values

Query parameters are bound using a DseGraphObject. Parameter values are added by name using the dse_graph_object_add_<type>() functions.

Copy
/* Create a system query (note: passing NULL for options) */
DseGraphStatement* statement =
  dse_graph_statement_new("system.graph(name).ifNotExists().create()", NULL);

/* Create a graph object to hold the query's parameters */
DseGraphObject* values = dse_graph_object_new();

/* Add the "name" parameter */
dse_graph_object_add_string(values, "name", "test");

/* Finish must be called after bind the last value */
dse_graph_object_finish(values);

/* Bind the value to the statement */
dse_graph_statement_bind_values(statement, values);

/* ... */

/* Cleanup */
dse_graph_object_free(values);

Handling results

Graph queries return a DseGraphResultSet which is able to iterate over the set of results. The lifetime of DseGraphResult objects are bound to the containing result set. DseGraphResult objects are invalidated with each call to dse_graph_resultset_next().

Copy
/* ... */

DseGraphResultSet* resultset = cass_future_get_dse_graph_resultset(future);

size_t i, count = dse_graph_resultset_count(resultset);

for (i = 0; i < count; ++i) {
  /* Gets the next result (and invalidateds the previous result */
  const DseGraphResult* result = dse_graph_resultset_next(resultset);

  /* ... */
}

/* Frees the result set and all contained `DseGraphResult` objects */
dse_graph_resultset_free(resultset);

A DseGraphResult is a variant type that can represent the following types: number (double or an integer), boolean, string, an array or an object (a collection of name/value pairs).

Copy

/* ... */

/* Always check the type of a DseGraphResult */
if (dse_graph_result_is_double(result)) {
  cass_double_t value = dse_graph_result_get_double(result);

  /* ... */
}

if (dse_graph_result_is_array(result)) {
  /* The count can be used to iterate over the elements in an array */
  size_t i, count = dse_graph_result_element_count(result);
  for (i = 0; i < count; ++i) {
    const DseGraphResult* element = dse_graph_result_element(result, i);

    /* ... */
  }
}

if (dse_graph_result_is_object(result)) {
  /* The count can be used to iterate over the members in an object */
  size_t i, count = dse_graph_result_member_count(result);
  for (i = 0; i < count; ++i) {
    const char* key = dse_graph_result_member_key(result, i, NULL);
    const DseGraphResult* value = dse_graph_result_member_value(result, i);

    /* ... */
  }
}