com.datastax.driver.dse.graph.GraphResultSet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dse-java-driver-core Show documentation
Show all versions of dse-java-driver-core Show documentation
A driver for DataStax Enterprise (DSE)
and Apache Cassandra 1.2+ clusters that works exclusively with the
Cassandra Query Language version 3 (CQL3) and Cassandra's binary protocol,
supporting DSE-specific features such as geospatial types, DSE Graph and DSE authentication.
/*
* Copyright (C) 2012-2017 DataStax Inc.
*
* This software can be used solely with DataStax Enterprise. Please consult the license at
* http://www.datastax.com/terms/datastax-dse-driver-license-terms
*/
package com.datastax.driver.dse.graph;
import com.datastax.driver.core.ExecutionInfo;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.exceptions.DriverException;
import com.datastax.driver.dse.DseSession;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Iterator;
import java.util.List;
/**
* The result of a graph query.
*/
public class GraphResultSet implements Iterable {
static final Function ROW_TO_DEFAULTGRAPHNODE = new Function() {
@Override
public GraphNode apply(Row row) {
// Seems like sometimes traversals can return empty rows
if (row != null) {
String jsonString = row.getString("gremlin");
try {
return GraphJsonUtils.readStringAsTree(jsonString);
} catch (RuntimeException e) {
throw new DriverException("Could not parse the result returned by the Graph server as a JSON string : " + jsonString, e);
}
} else {
return null;
}
}
};
private long bulk = 0;
private GraphNode lastGraphNode = null;
private final ResultSet wrapped;
private final Function transformResultFunction;
/**
* This constructor is intended for internal use only, users should normally obtain instances from
* {@link DseSession#executeGraph(GraphStatement)}.
*/
public GraphResultSet(ResultSet wrapped) {
this(wrapped, ROW_TO_DEFAULTGRAPHNODE);
}
public GraphResultSet(ResultSet wrapped, Function transformResultFunction) {
this.wrapped = wrapped;
this.transformResultFunction = transformResultFunction;
}
/**
* Returns whether there are more results.
*
* @return whether there are more results.
*/
public boolean isExhausted() {
return wrapped.isExhausted() && bulk <= 1;
}
/**
* Returns the next result.
*
* @return the next result, or {@code null} if there are no more of them.
*/
public GraphNode one() {
if (bulk > 1) {
bulk--;
// TODO: return a copy? Not sure it's useful because the content of this is supposed to be immutable.
return lastGraphNode;
}
GraphNode container = this.transformResultFunction.apply(wrapped.one());
if (container == null) {
return null;
}
if (container.get(GraphSONTokens.BULK) != null) {
bulk = container.get(GraphSONTokens.BULK).asLong();
}
GraphNode results = container.get("result");
lastGraphNode = results;
return results;
}
/**
* Returns all the remaining results as a list.
*
* @return a list containing the remaining results. The result set will be exhausted after a call to this method.
*/
public List all() {
return ImmutableList.copyOf(iterator());
}
/**
* Returns an iterator over the results.
*
* The {@link Iterator#next} method is equivalent to calling {@link #one}. After a full iteration, the result set
* will be exhausted.
*
* The returned iterator does not support the {@link Iterator#remove} method.
*
* @return an iterator that will consume and return the remaining results.
*/
public Iterator iterator() {
return new Iterator() {
@Override
public boolean hasNext() {
return !isExhausted();
}
@Override
public GraphNode next() {
return one();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* This method has been deprecated because it may return incorrect numbers. Since paging
* is not implemented in DSE Graph, using {@link #all()} is recommended instead to gather all
* the results coming back from a DSE Graph query.
*
* The number of results that can be retrieved without blocking to fetch.
*
* @return the number of results readily available. If {@link #isFullyFetched()}, this is the total number of
* results remaining, otherwise going past that limit will trigger background fetches.
*/
@Deprecated
public int getAvailableWithoutFetching() {
return wrapped.getAvailableWithoutFetching();
}
/**
* This method has been deprecated because paging is not implemented for DSE Graph.
*
* Whether all results have been fetched from the database.
*
* If {@code isFullyFetched()}, then {@link #getAvailableWithoutFetching} will return the number of results
* remaining before exhaustion.
*
* But {@code !isFullyFetched()} does not necessarily mean that the result set is not exhausted (you should call
* {@code isExhausted()} to verify it).
*
* @return whether all results have been fetched.
*/
@Deprecated
public boolean isFullyFetched() {
return wrapped.isFullyFetched();
}
/**
* This method has been deprecated because paging is not implemented for DSE Graph.
*
* Force fetching the next page of results for this result set, if any.
*
* This method is entirely optional. It will be called automatically while
* the result set is consumed (through {@link #one}, {@link #all} or iteration)
* when needed (i.e. when {@code getAvailableWithoutFetching() == 0} and
* {@code isFullyFetched() == false}).
*
* You can however call this method manually to force the fetching of the
* next page of results. This can allow to prefetch results before they are
* strictly needed. For instance, if you want to prefetch the next page of
* results as soon as there is less than 100 rows readily available in this
* result set, you can do:
*
* GraphResultSet rs = session.executeGraph(...);
* Iterator<GraphNode> iter = rs.iterator();
* while (iter.hasNext()) {
* if (rs.getAvailableWithoutFetching() == 100 && !rs.isFullyFetched())
* rs.fetchMoreResults();
* GraphNode result = iter.next()
* ... process the result ...
* }
*
* This method is not blocking, so in the example above, the call to {@code
* fetchMoreResults} will not block the processing of the 100 currently available
* results (but {@code iter.hasNext()} will block once those results have been processed
* until the fetch query returns, if it hasn't yet).
*
* Only one page of results (for a given result set) can be
* fetched at any given time. If this method is called twice and the query
* triggered by the first call has not returned yet when the second one is
* performed, then the 2nd call will simply return a future on the currently
* in progress query.
*
* @return a future on the completion of fetching the next page of results.
* If the result set is already fully retrieved ({@code isFullyFetched() == true}),
* then the returned future will return immediately, but not particular error will be
* thrown (you should thus call {@code isFullyFetched() to know if calling this
* method can be of any use}).
*/
@Deprecated
public ListenableFuture fetchMoreResults() {
return Futures.transform(wrapped.fetchMoreResults(), new Function() {
@Override
public GraphResultSet apply(ResultSet input) {
return new GraphResultSet(input, transformResultFunction);
}
});
}
/**
* Returns information on the execution of the last query made for this result set.
*
* Note that in most cases, a result set is fetched with only one query, but large
* result sets can be paged and thus be retrieved by multiple queries. In that
* case this method return the {@code ExecutionInfo} for the last query
* performed. To retrieve the information for all queries, use {@link #getAllExecutionInfo}.
*
* The returned object includes basic information such as the queried hosts,
* but also the Cassandra query trace if tracing was enabled for the query.
*
* @return the execution info for the last query made for this GraphResultSet.
*/
public ExecutionInfo getExecutionInfo() {
return wrapped.getExecutionInfo();
}
/**
* Returns the execution information for all queries made to retrieve this result set.
*
* If paging was used, the returned list contains the {@code ExecutionInfo} for all the queries done to obtain the
* results (at the time of the call), in the order those queries were made.
*
* If no paging was used (because the result set was small enough), the list only contains one element.
*
* @return a list of the execution info for all the queries made for this GraphResultSet.
*/
public List getAllExecutionInfo() {
return wrapped.getAllExecutionInfo();
}
}