package org.vertexium;
import com.google.common.collect.Sets;
import org.vertexium.event.GraphEvent;
import org.vertexium.event.GraphEventListener;
import org.vertexium.id.IdGenerator;
import org.vertexium.mutation.ElementMutation;
import org.vertexium.mutation.ExistingElementMutation;
import org.vertexium.property.StreamingPropertyValue;
import org.vertexium.property.StreamingPropertyValueRef;
import org.vertexium.query.GraphQuery;
import org.vertexium.query.MultiVertexQuery;
import org.vertexium.query.SimilarToGraphQuery;
import org.vertexium.util.*;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
import static org.vertexium.util.IterableUtils.count;
import static org.vertexium.util.Preconditions.checkNotNull;
import static org.vertexium.util.StreamUtils.stream;
public abstract class GraphBase implements Graph {
private static final VertexiumLogger LOGGER = VertexiumLoggerFactory.getLogger(GraphBase.class);
protected static final VertexiumLogger QUERY_LOGGER = VertexiumLoggerFactory.getQueryLogger(Graph.class);
public static final String METADATA_DEFINE_PROPERTY_PREFIX = "defineProperty.";
private final List<GraphEventListener> graphEventListeners = new ArrayList<>();
private Map<String, PropertyDefinition> propertyDefinitionCache = new HashMap<>();
private final boolean strictTyping;
protected GraphBase(boolean strictTyping) {
this.strictTyping = strictTyping;
}
@Override
public Vertex addVertex(Visibility visibility, Authorizations authorizations) {
return prepareVertex(visibility).save(authorizations);
}
@Override
public Vertex addVertex(String vertexId, Visibility visibility, Authorizations authorizations) {
return prepareVertex(vertexId, visibility).save(authorizations);
}
@Override
public Iterable<Vertex> addVertices(Iterable<ElementBuilder<Vertex>> vertices, Authorizations authorizations) {
List<Vertex> addedVertices = new ArrayList<>();
for (ElementBuilder<Vertex> vertexBuilder : vertices) {
addedVertices.add(vertexBuilder.save(authorizations));
}
return addedVertices;
}
@Override
public VertexBuilder prepareVertex(Visibility visibility) {
return prepareVertex(getIdGenerator().nextId(), null, visibility);
}
@Override
public abstract VertexBuilder prepareVertex(String vertexId, Long timestamp, Visibility visibility);
@Override
public VertexBuilder prepareVertex(Long timestamp, Visibility visibility) {
return prepareVertex(getIdGenerator().nextId(), timestamp, visibility);
}
@Override
public VertexBuilder prepareVertex(String vertexId, Visibility visibility) {
return prepareVertex(vertexId, null, visibility);
}
@Override
public boolean doesVertexExist(String vertexId, Authorizations authorizations) {
return getVertex(vertexId, FetchHint.NONE, authorizations) != null;
}
@Override
public Vertex getVertex(String vertexId, EnumSet<FetchHint> fetchHints, Authorizations authorizations) {
return getVertex(vertexId, fetchHints, null, authorizations);
}
@Override
public Vertex getVertex(String vertexId, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations) {
for (Vertex vertex : getVertices(fetchHints, endTime, authorizations)) {
if (vertex.getId().equals(vertexId)) {
return vertex;
}
}
return null;
}
@Override
public Vertex getVertex(String vertexId, Authorizations authorizations) throws VertexiumException {
return getVertex(vertexId, getDefaultFetchHints(), authorizations);
}
@Override
public Iterable<Vertex> getVerticesWithPrefix(String vertexIdPrefix, Authorizations authorizations) {
return getVerticesWithPrefix(vertexIdPrefix, getDefaultFetchHints(), authorizations);
}
@Override
public Iterable<Vertex> getVerticesWithPrefix(String vertexIdPrefix, EnumSet<FetchHint> fetchHints, Authorizations authorizations) {
return getVerticesWithPrefix(vertexIdPrefix, fetchHints, null, authorizations);
}
@Override
public Iterable<Vertex> getVerticesWithPrefix(final String vertexIdPrefix, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations) {
Iterable<Vertex> vertices = getVertices(fetchHints, endTime, authorizations);
return new FilterIterable<Vertex>(vertices) {
@Override
protected boolean isIncluded(Vertex v) {
return v.getId().startsWith(vertexIdPrefix);
}
};
}
@Override
public Iterable<Vertex> getVerticesInRange(Range idRange, Authorizations authorizations) {
return getVerticesInRange(idRange, getDefaultFetchHints(), authorizations);
}
@Override
public Iterable<Vertex> getVerticesInRange(Range idRange, EnumSet<FetchHint> fetchHints, Authorizations authorizations) {
return getVerticesInRange(idRange, fetchHints, null, authorizations);
}
@Override
public Iterable<Vertex> getVerticesInRange(final Range idRange, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations) {
Iterable<Vertex> vertices = getVertices(fetchHints, endTime, authorizations);
return new FilterIterable<Vertex>(vertices) {
@Override
protected boolean isIncluded(Vertex v) {
return idRange.isInRange(v.getId());
}
};
}
@Override
public Iterable<Vertex> getVertices(final Iterable<String> ids, EnumSet<FetchHint> fetchHints, final Authorizations authorizations) {
return getVertices(ids, fetchHints, null, authorizations);
}
@Override
public Iterable<Vertex> getVertices(final Iterable<String> ids, final EnumSet<FetchHint> fetchHints, final Long endTime, final Authorizations authorizations) {
return new LookAheadIterable<String, Vertex>() {
@Override
protected boolean isIncluded(String src, Vertex vertex) {
return vertex != null;
}
@Override
protected Vertex convert(String id) {
return getVertex(id, fetchHints, endTime, authorizations);
}
@Override
protected Iterator<String> createIterator() {
return Sets.newHashSet(ids).iterator();
}
};
}
@Override
public Map<String, Boolean> doVerticesExist(Iterable<String> ids, Authorizations authorizations) {
Map<String, Boolean> results = new HashMap<>();
for (String id : ids) {
results.put(id, false);
}
for (Vertex vertex : getVertices(ids, FetchHint.NONE, authorizations)) {
results.put(vertex.getId(), true);
}
return results;
}
@Override
public Iterable<Vertex> getVertices(final Iterable<String> ids, final Authorizations authorizations) {
return getVertices(ids, getDefaultFetchHints(), authorizations);
}
@Override
public List<Vertex> getVerticesInOrder(Iterable<String> ids, EnumSet<FetchHint> fetchHints, Authorizations authorizations) {
final List<String> vertexIds = IterableUtils.toList(ids);
List<Vertex> vertices = IterableUtils.toList(getVertices(vertexIds, authorizations));
vertices.sort((v1, v2) -> {
Integer i1 = vertexIds.indexOf(v1.getId());
Integer i2 = vertexIds.indexOf(v2.getId());
return i1.compareTo(i2);
});
return vertices;
}
@Override
public List<Vertex> getVerticesInOrder(Iterable<String> ids, Authorizations authorizations) {
return getVerticesInOrder(ids, getDefaultFetchHints(), authorizations);
}
@Override
public Iterable<Vertex> getVertices(Authorizations authorizations) throws VertexiumException {
return getVertices(getDefaultFetchHints(), authorizations);
}
@Override
public Iterable<Vertex> getVertices(EnumSet<FetchHint> fetchHints, Authorizations authorizations) {
return getVertices(fetchHints, null, authorizations);
}
@Override
public abstract Iterable<Vertex> getVertices(EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations);
@Override
public Edge addEdge(Vertex outVertex, Vertex inVertex, String label, Visibility visibility, Authorizations authorizations) {
return prepareEdge(outVertex, inVertex, label, visibility).save(authorizations);
}
@Override
public Edge addEdge(String edgeId, Vertex outVertex, Vertex inVertex, String label, Visibility visibility, Authorizations authorizations) {
return prepareEdge(edgeId, outVertex, inVertex, label, visibility).save(authorizations);
}
@Override
public Edge addEdge(String outVertexId, String inVertexId, String label, Visibility visibility, Authorizations authorizations) {
return prepareEdge(outVertexId, inVertexId, label, visibility).save(authorizations);
}
@Override
public Edge addEdge(String edgeId, String outVertexId, String inVertexId, String label, Visibility visibility, Authorizations authorizations) {
return prepareEdge(edgeId, outVertexId, inVertexId, label, visibility).save(authorizations);
}
@Override
public EdgeBuilderByVertexId prepareEdge(String outVertexId, String inVertexId, String label, Visibility visibility) {
return prepareEdge(getIdGenerator().nextId(), outVertexId, inVertexId, label, visibility);
}
@Override
public EdgeBuilder prepareEdge(Vertex outVertex, Vertex inVertex, String label, Visibility visibility) {
return prepareEdge(getIdGenerator().nextId(), outVertex, inVertex, label, visibility);
}
@Override
public EdgeBuilder prepareEdge(String edgeId, Vertex outVertex, Vertex inVertex, String label, Visibility visibility) {
return prepareEdge(edgeId, outVertex, inVertex, label, null, visibility);
}
@Override
public abstract EdgeBuilder prepareEdge(String edgeId, Vertex outVertex, Vertex inVertex, String label, Long timestamp, Visibility visibility);
@Override
public EdgeBuilderByVertexId prepareEdge(String edgeId, String outVertexId, String inVertexId, String label, Visibility visibility) {
return prepareEdge(edgeId, outVertexId, inVertexId, label, null, visibility);
}
@Override
public abstract EdgeBuilderByVertexId prepareEdge(String edgeId, String outVertexId, String inVertexId, String label, Long timestamp, Visibility visibility);
@Override
public boolean doesEdgeExist(String edgeId, Authorizations authorizations) {
return getEdge(edgeId, FetchHint.NONE, authorizations) != null;
}
@Override
public Edge getEdge(String edgeId, EnumSet<FetchHint> fetchHints, Authorizations authorizations) {
return getEdge(edgeId, fetchHints, null, authorizations);
}
@Override
public Edge getEdge(String edgeId, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations) {
for (Edge edge : getEdges(fetchHints, endTime, authorizations)) {
if (edge.getId().equals(edgeId)) {
return edge;
}
}
return null;
}
@Override
public Edge getEdge(String edgeId, Authorizations authorizations) {
return getEdge(edgeId, getDefaultFetchHints(), authorizations);
}
@Override
public Map<String, Boolean> doEdgesExist(Iterable<String> ids, Authorizations authorizations) {
return doEdgesExist(ids, null, authorizations);
}
@Override
public Map<String, Boolean> doEdgesExist(Iterable<String> ids, Long endTime, Authorizations authorizations) {
Map<String, Boolean> results = new HashMap<>();
for (String id : ids) {
results.put(id, false);
}
for (Edge edge : getEdges(ids, FetchHint.NONE, endTime, authorizations)) {
results.put(edge.getId(), true);
}
return results;
}
@Override
public void deleteVertex(String vertexId, Authorizations authorizations) {
Vertex vertex = getVertex(vertexId, authorizations);
checkNotNull(vertex, "Could not find vertex to delete with id: " + vertexId);
deleteVertex(vertex, authorizations);
}
@Override
public void deleteEdge(String edgeId, Authorizations authorizations) {
Edge edge = getEdge(edgeId, authorizations);
checkNotNull(edge, "Could not find edge to delete with id: " + edgeId);
deleteEdge(edge, authorizations);
}
@Override
public void softDeleteVertex(String vertexId, Authorizations authorizations) {
Vertex vertex = getVertex(vertexId, authorizations);
checkNotNull(vertex, "Could not find vertex to soft delete with id: " + vertexId);
softDeleteVertex(vertex, null, authorizations);
}
@Override
public void softDeleteVertex(String vertexId, Long timestamp, Authorizations authorizations) {
Vertex vertex = getVertex(vertexId, authorizations);
checkNotNull(vertex, "Could not find vertex to soft delete with id: " + vertexId);
softDeleteVertex(vertex, timestamp, authorizations);
}
@Override
public void softDeleteVertex(Vertex vertex, Authorizations authorizations) {
softDeleteVertex(vertex, null, authorizations);
}
@Override
public abstract void softDeleteVertex(Vertex vertex, Long timestamp, Authorizations authorizations);
@Override
public void softDeleteEdge(String edgeId, Authorizations authorizations) {
Edge edge = getEdge(edgeId, authorizations);
checkNotNull(edge, "Could not find edge to soft delete with id: " + edgeId);
softDeleteEdge(edge, null, authorizations);
}
@Override
public void softDeleteEdge(String edgeId, Long timestamp, Authorizations authorizations) {
Edge edge = getEdge(edgeId, authorizations);
checkNotNull(edge, "Could not find edge to soft delete with id: " + edgeId);
softDeleteEdge(edge, timestamp, authorizations);
}
@Override
public void softDeleteEdge(Edge edge, Authorizations authorizations) {
softDeleteEdge(edge, null, authorizations);
}
@Override
public abstract void softDeleteEdge(Edge edge, Long timestamp, Authorizations authorizations);
@Override
public Iterable<String> filterEdgeIdsByAuthorization(
Iterable<String> edgeIds,
final String authorizationToMatch,
final EnumSet<ElementFilter> filters,
Authorizations authorizations
) {
FilterIterable<Edge> edges = new FilterIterable<Edge>(getEdges(edgeIds, FetchHint.ALL_INCLUDING_HIDDEN, authorizations)) {
@Override
protected boolean isIncluded(Edge edge) {
if (filters.contains(ElementFilter.ELEMENT)) {
if (edge.getVisibility().hasAuthorization(authorizationToMatch)) {
return true;
}
}
return isIncludedByAuthorizations(edge, filters, authorizationToMatch);
}
};
return new ConvertingIterable<Edge, String>(edges) {
@Override
protected String convert(Edge edge) {
return edge.getId();
}
};
}
private boolean isIncludedByAuthorizations(Element element, EnumSet<ElementFilter> filters, String authorizationToMatch) {
if (filters.contains(ElementFilter.PROPERTY) || filters.contains(ElementFilter.PROPERTY_METADATA)) {
for (Property property : element.getProperties()) {
if (filters.contains(ElementFilter.PROPERTY)) {
if (property.getVisibility().hasAuthorization(authorizationToMatch)) {
return true;
}
}
if (filters.contains(ElementFilter.PROPERTY_METADATA)) {
for (Metadata.Entry entry : property.getMetadata().entrySet()) {
if (entry.getVisibility().hasAuthorization(authorizationToMatch)) {
return true;
}
}
}
}
}
return false;
}
@Override
public Iterable<String> filterVertexIdsByAuthorization(
Iterable<String> vertexIds,
final String authorizationToMatch,
final EnumSet<ElementFilter> filters,
Authorizations authorizations
) {
FilterIterable<Vertex> vertices = new FilterIterable<Vertex>(getVertices(vertexIds, FetchHint.ALL_INCLUDING_HIDDEN, authorizations)) {
@Override
protected boolean isIncluded(Vertex vertex) {
if (filters.contains(ElementFilter.ELEMENT)) {
if (vertex.getVisibility().hasAuthorization(authorizationToMatch)) {
return true;
}
}
return isIncludedByAuthorizations(vertex, filters, authorizationToMatch);
}
};
return new ConvertingIterable<Vertex, String>(vertices) {
@Override
protected String convert(Vertex vertex) {
return vertex.getId();
}
};
}
@Override
public Iterable<Edge> getEdges(final Iterable<String> ids, final EnumSet<FetchHint> fetchHints, final Authorizations authorizations) {
return getEdges(ids, fetchHints, null, authorizations);
}
@Override
public Iterable<Edge> getEdges(final Iterable<String> ids, final EnumSet<FetchHint> fetchHints, final Long endTime, final Authorizations authorizations) {
return new LookAheadIterable<String, Edge>() {
@Override
protected boolean isIncluded(String src, Edge edge) {
return edge != null;
}
@Override
protected Edge convert(String id) {
return getEdge(id, fetchHints, endTime, authorizations);
}
@Override
protected Iterator<String> createIterator() {
return Sets.newHashSet(ids).iterator();
}
};
}
@Override
public Iterable<Edge> getEdges(final Iterable<String> ids, final Authorizations authorizations) {
return getEdges(ids, getDefaultFetchHints(), authorizations);
}
@Override
public Iterable<Edge> getEdges(Authorizations authorizations) {
return getEdges(getDefaultFetchHints(), authorizations);
}
@Override
public Iterable<Edge> getEdges(EnumSet<FetchHint> fetchHints, Authorizations authorizations) {
return getEdges(fetchHints, null, authorizations);
}
@Override
public abstract Iterable<Edge> getEdges(EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations);
@Override
public Iterable<Edge> getEdgesInRange(Range idRange, Authorizations authorizations) {
return getEdgesInRange(idRange, getDefaultFetchHints(), authorizations);
}
@Override
public Iterable<Edge> getEdgesInRange(Range idRange, EnumSet<FetchHint> fetchHints, Authorizations authorizations) {
return getEdgesInRange(idRange, fetchHints, null, authorizations);
}
@Override
public Iterable<Edge> getEdgesInRange(final Range idRange, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations) {
Iterable<Edge> edges = getEdges(fetchHints, endTime, authorizations);
return new FilterIterable<Edge>(edges) {
@Override
protected boolean isIncluded(Edge e) {
return idRange.isInRange(e.getId());
}
};
}
@Override
@Deprecated
public Iterable<Path> findPaths(String sourceVertexId, String destVertexId, int maxHops, Authorizations authorizations) {
return findPaths(sourceVertexId, destVertexId, null, maxHops, authorizations);
}
@Override
@Deprecated
public Iterable<Path> findPaths(String sourceVertexId, String destVertexId, String[] labels, int maxHops, Authorizations authorizations) {
return findPaths(sourceVertexId, destVertexId, labels, maxHops, null, authorizations);
}
@Override
@Deprecated
public Iterable<Path> findPaths(String sourceVertexId, String destVertexId, int maxHops, ProgressCallback progressCallback, Authorizations authorizations) {
return findPaths(sourceVertexId, destVertexId, null, maxHops, progressCallback, authorizations);
}
@Override
@Deprecated
public Iterable<Path> findPaths(String sourceVertexId, String destVertexId, String[] labels, int maxHops, ProgressCallback progressCallback, Authorizations authorizations) {
FindPathOptions options = new FindPathOptions(sourceVertexId, destVertexId, maxHops);
options.setLabels(labels);
options.setProgressCallback(progressCallback);
return findPaths(options, authorizations);
}
@Override
public Iterable<Path> findPaths(FindPathOptions options, Authorizations authorizations) {
ProgressCallback progressCallback = options.getProgressCallback();
if (progressCallback == null) {
progressCallback = new ProgressCallback() {
@Override
public void progress(double progressPercent, Step step, Integer edgeIndex, Integer vertexCount) {
LOGGER.debug("findPaths progress %d%%: %s", (int) (progressPercent * 100.0), step.formatMessage(edgeIndex, vertexCount));
}
};
}
EnumSet<FetchHint> fetchHints = FetchHint.EDGE_REFS;
Vertex sourceVertex = getVertex(options.getSourceVertexId(), fetchHints, authorizations);
if (sourceVertex == null) {
throw new IllegalArgumentException("Could not find vertex with id: " + options.getSourceVertexId());
}
Vertex destVertex = getVertex(options.getDestVertexId(), fetchHints, authorizations);
if (destVertex == null) {
throw new IllegalArgumentException("Could not find vertex with id: " + options.getDestVertexId());
}
progressCallback.progress(0, ProgressCallback.Step.FINDING_PATH);
Set<String> seenVertices = new HashSet<>();
seenVertices.add(sourceVertex.getId());
Path startPath = new Path(sourceVertex.getId());
List<Path> foundPaths = new ArrayList<>();
if (options.getMaxHops() == 2) {
findPathsSetIntersection(
options,
foundPaths,
sourceVertex,
destVertex,
progressCallback,
authorizations
);
} else {
findPathsRecursive(
options,
foundPaths,
sourceVertex,
destVertex,
options.getMaxHops(),
seenVertices,
startPath,
progressCallback,
authorizations
);
}
progressCallback.progress(1, ProgressCallback.Step.COMPLETE);
return foundPaths;
}
protected void findPathsSetIntersection(FindPathOptions options, List<Path> foundPaths, Vertex sourceVertex, Vertex destVertex, ProgressCallback progressCallback, Authorizations authorizations) {
String sourceVertexId = sourceVertex.getId();
String destVertexId = destVertex.getId();
progressCallback.progress(0.1, ProgressCallback.Step.SEARCHING_SOURCE_VERTEX_EDGES);
Set<String> sourceVertexConnectedVertexIds = filterFindPathEdgeInfo(options, sourceVertex.getEdgeInfos(Direction.BOTH, options.getLabels(), authorizations));
progressCallback.progress(0.3, ProgressCallback.Step.SEARCHING_DESTINATION_VERTEX_EDGES);
Set<String> destVertexConnectedVertexIds = filterFindPathEdgeInfo(options, destVertex.getEdgeInfos(Direction.BOTH, options.getLabels(), authorizations));
if (sourceVertexConnectedVertexIds.contains(destVertexId)) {
foundPaths.add(new Path(sourceVertexId, destVertexId));
if (options.isGetAnyPath()) {
return;
}
}
progressCallback.progress(0.6, ProgressCallback.Step.MERGING_EDGES);
sourceVertexConnectedVertexIds.retainAll(destVertexConnectedVertexIds);
progressCallback.progress(0.9, ProgressCallback.Step.ADDING_PATHS);
for (String connectedVertexId : sourceVertexConnectedVertexIds) {
foundPaths.add(new Path(sourceVertexId, connectedVertexId, destVertexId));
}
}
private Set<String> filterFindPathEdgeInfo(FindPathOptions options, Iterable<EdgeInfo> edgeInfos) {
return stream(edgeInfos)
.filter(edgeInfo -> {
if (options.getExcludedLabels() != null) {
return !ArrayUtils.contains(options.getExcludedLabels(), edgeInfo.getLabel());
}
return true;
})
.map(EdgeInfo::getVertexId)
.collect(Collectors.toSet());
}
private Iterable<Vertex> filterFindPathEdgePairs(FindPathOptions options, Iterable<EdgeVertexPair> edgeVertexPairs) {
return stream(edgeVertexPairs)
.filter(edgePair -> {
if (options.getExcludedLabels() != null) {
return !ArrayUtils.contains(options.getExcludedLabels(), edgePair.getEdge().getLabel());
}
return true;
})
.map(EdgeVertexPair::getVertex)
.collect(Collectors.toList());
}
protected void findPathsRecursive(
FindPathOptions options,
List<Path> foundPaths,
Vertex sourceVertex,
Vertex destVertex,
int hops,
Set<String> seenVertices,
Path currentPath,
ProgressCallback progressCallback,
Authorizations authorizations
) {
// if this is our first source vertex report progress back to the progress callback
boolean firstLevelRecursion = hops == options.getMaxHops();
if (options.isGetAnyPath() && foundPaths.size() == 1) {
return;
}
seenVertices.add(sourceVertex.getId());
if (sourceVertex.getId().equals(destVertex.getId())) {
foundPaths.add(currentPath);
} else if (hops > 0) {
Iterable<Vertex> vertices = filterFindPathEdgePairs(options, sourceVertex.getEdgeVertexPairs(Direction.BOTH, options.getLabels(), authorizations));
int vertexCount = 0;
if (firstLevelRecursion) {
vertices = IterableUtils.toList(vertices);
vertexCount = ((List<Vertex>) vertices).size();
}
int i = 0;
for (Vertex child : vertices) {
if (firstLevelRecursion) {
// this will never get to 100% since i starts at 0. which is good. 100% signifies done and we still have work to do.
double progressPercent = (double) i / (double) vertexCount;
progressCallback.progress(progressPercent, ProgressCallback.Step.SEARCHING_EDGES, i + 1, vertexCount);
}
if (!seenVertices.contains(child.getId())) {
findPathsRecursive(options, foundPaths, child, destVertex, hops - 1, seenVertices, new Path(currentPath, child.getId()), progressCallback, authorizations);
}
i++;
}
}
seenVertices.remove(sourceVertex.getId());
}
@Override
@Deprecated
public Iterable<String> findRelatedEdges(Iterable<String> vertexIds, Authorizations authorizations) {
return findRelatedEdgeIds(vertexIds, authorizations);
}
@Override
@Deprecated
public Iterable<String> findRelatedEdges(Iterable<String> vertexIds, Long endTime, Authorizations authorizations) {
return findRelatedEdgeIds(vertexIds, endTime, authorizations);
}
@Override
public Iterable<String> findRelatedEdgeIds(Iterable<String> vertexIds, Authorizations authorizations) {
return findRelatedEdgeIds(vertexIds, null, authorizations);
}
@Override
public Iterable<String> findRelatedEdgeIds(Iterable<String> vertexIds, Long endTime, Authorizations authorizations) {
return findRelatedEdgeIdsForVertices(getVertices(vertexIds, EnumSet.of(FetchHint.OUT_EDGE_REFS), endTime, authorizations), authorizations);
}
@Override
public Iterable<RelatedEdge> findRelatedEdgeSummary(Iterable<String> vertexIds, Authorizations authorizations) {
return findRelatedEdgeSummary(vertexIds, null, authorizations);
}
@Override
public Iterable<RelatedEdge> findRelatedEdgeSummary(Iterable<String> vertexIds, Long endTime, Authorizations authorizations) {
return findRelatedEdgeSummaryForVertices(getVertices(vertexIds, EnumSet.of(FetchHint.OUT_EDGE_REFS), endTime, authorizations), authorizations);
}
@Override
public Iterable<RelatedEdge> findRelatedEdgeSummaryForVertices(Iterable<Vertex> verticesIterable, Authorizations authorizations) {
List<RelatedEdge> results = new ArrayList<>();
List<Vertex> vertices = IterableUtils.toList(verticesIterable);
for (Vertex outVertex : vertices) {
Iterable<EdgeInfo> edgeInfos = outVertex.getEdgeInfos(Direction.OUT, authorizations);
for (EdgeInfo edgeInfo : edgeInfos) {
for (Vertex inVertex : vertices) {
if (edgeInfo.getVertexId().equals(inVertex.getId())) {
results.add(new RelatedEdgeImpl(edgeInfo.getEdgeId(), edgeInfo.getLabel(), outVertex.getId(), inVertex.getId()));
}
}
}
}
return results;
}
@Override
public Iterable<String> findRelatedEdgeIdsForVertices(Iterable<Vertex> verticesIterable, Authorizations authorizations) {
List<String> results = new ArrayList<>();
List<Vertex> vertices = IterableUtils.toList(verticesIterable);
for (Vertex outVertex : vertices) {
if (outVertex == null) {
throw new VertexiumException("verticesIterable cannot have null values");
}
Iterable<EdgeInfo> edgeInfos = outVertex.getEdgeInfos(Direction.OUT, authorizations);
for (EdgeInfo edgeInfo : edgeInfos) {
for (Vertex inVertex : vertices) {
if (edgeInfo.getVertexId() == null) { // This check is for legacy data. null EdgeInfo.vertexIds are no longer permitted
continue;
}
if (edgeInfo.getVertexId().equals(inVertex.getId())) {
results.add(edgeInfo.getEdgeId());
}
}
}
}
return results;
}
protected abstract GraphMetadataStore getGraphMetadataStore();
@Override
public final Iterable<GraphMetadataEntry> getMetadata() {
return getGraphMetadataStore().getMetadata();
}
@Override
public final void setMetadata(String key, Object value) {
getGraphMetadataStore().setMetadata(key, value);
}
@Override
public final Object getMetadata(String key) {
return getGraphMetadataStore().getMetadata(key);
}
@Override
public final Iterable<GraphMetadataEntry> getMetadataWithPrefix(String prefix) {
return getGraphMetadataStore().getMetadataWithPrefix(prefix);
}
@Override
public abstract GraphQuery query(Authorizations authorizations);
@Override
public abstract GraphQuery query(String queryString, Authorizations authorizations);
@Override
public abstract void reindex(Authorizations authorizations);
@Override
public abstract void flush();
@Override
public abstract void shutdown();
@Override
public abstract void drop();
@Override
public abstract boolean isFieldBoostSupported();
@Override
public abstract SearchIndexSecurityGranularity getSearchIndexSecurityGranularity();
@Override
public void addGraphEventListener(GraphEventListener graphEventListener) {
this.graphEventListeners.add(graphEventListener);
}
protected boolean hasEventListeners() {
return this.graphEventListeners.size() > 0;
}
protected void fireGraphEvent(GraphEvent graphEvent) {
for (GraphEventListener graphEventListener : this.graphEventListeners) {
graphEventListener.onGraphEvent(graphEvent);
}
}
@Override
public boolean isQuerySimilarToTextSupported() {
return false;
}
@Override
public SimilarToGraphQuery querySimilarTo(String[] fields, String text, Authorizations authorizations) {
throw new VertexiumException("querySimilarTo not supported");
}
@Override
public Authorizations createAuthorizations(Collection<String> auths) {
checkNotNull(auths, "auths cannot be null");
return createAuthorizations(auths.toArray(new String[auths.size()]));
}
@Override
public Authorizations createAuthorizations(Authorizations auths, String... additionalAuthorizations) {
Set<String> newAuths = new HashSet<>();
Collections.addAll(newAuths, auths.getAuthorizations());
Collections.addAll(newAuths, additionalAuthorizations);
return createAuthorizations(newAuths);
}
@Override
public Authorizations createAuthorizations(Authorizations auths, Collection<String> additionalAuthorizations) {
return createAuthorizations(auths, additionalAuthorizations.toArray(new String[additionalAuthorizations.size()]));
}
@Override
public Map<Object, Long> getVertexPropertyCountByValue(String propertyName, Authorizations authorizations) {
Map<Object, Long> countsByValue = new HashMap<>();
for (Vertex v : getVertices(authorizations)) {
for (Property p : v.getProperties()) {
if (propertyName.equals(p.getName())) {
Object mapKey = p.getValue();
if (mapKey instanceof String) {
mapKey = ((String) mapKey).toLowerCase();
}
Long currentValue = countsByValue.get(mapKey);
if (currentValue == null) {
countsByValue.put(mapKey, 1L);
} else {
countsByValue.put(mapKey, currentValue + 1);
}
}
}
}
return countsByValue;
}
@Override
public long getVertexCount(Authorizations authorizations) {
return count(getVertices(authorizations));
}
@Override
public long getEdgeCount(Authorizations authorizations) {
return count(getEdges(authorizations));
}
@Override
public abstract void deleteVertex(Vertex vertex, Authorizations authorizations);
@Override
public abstract void deleteEdge(Edge edge, Authorizations authorizations);
@Override
public abstract void deleteExtendedDataRow(ExtendedDataRowId id, Authorizations authorizations);
@Override
public abstract MultiVertexQuery query(String[] vertexIds, String queryString, Authorizations authorizations);
@Override
public abstract MultiVertexQuery query(String[] vertexIds, Authorizations authorizations);
@Override
public abstract IdGenerator getIdGenerator();
@Override
public abstract boolean isVisibilityValid(Visibility visibility, Authorizations authorizations);
@Override
public abstract void truncate();
@Override
public abstract void markVertexHidden(Vertex vertex, Visibility visibility, Authorizations authorizations);
@Override
public abstract void markVertexVisible(Vertex vertex, Visibility visibility, Authorizations authorizations);
@Override
public abstract void markEdgeHidden(Edge edge, Visibility visibility, Authorizations authorizations);
@Override
public abstract void markEdgeVisible(Edge edge, Visibility visibility, Authorizations authorizations);
@Override
public abstract Authorizations createAuthorizations(String... auths);
@Override
public DefinePropertyBuilder defineProperty(String propertyName) {
return new DefinePropertyBuilder(propertyName) {
@Override
public PropertyDefinition define() {
PropertyDefinition propertyDefinition = super.define();
savePropertyDefinition(propertyDefinition);
return propertyDefinition;
}
};
}
protected void addToPropertyDefinitionCache(PropertyDefinition propertyDefinition) {
propertyDefinitionCache.put(propertyDefinition.getPropertyName(), propertyDefinition);
}
public void savePropertyDefinition(PropertyDefinition propertyDefinition) {
addToPropertyDefinitionCache(propertyDefinition);
setMetadata(getPropertyDefinitionKey(propertyDefinition.getPropertyName()), propertyDefinition);
}
private String getPropertyDefinitionKey(String propertyName) {
return METADATA_DEFINE_PROPERTY_PREFIX + propertyName;
}
@Override
public PropertyDefinition getPropertyDefinition(String propertyName) {
PropertyDefinition propertyDefinition = propertyDefinitionCache.get(propertyName);
if (propertyDefinition != null) {
return propertyDefinition;
}
propertyDefinition = (PropertyDefinition) getMetadata(getPropertyDefinitionKey(propertyName));
if (propertyDefinition != null) {
propertyDefinitionCache.put(propertyName, propertyDefinition);
}
return propertyDefinition;
}
@Override
public Collection<PropertyDefinition> getPropertyDefinitions() {
return propertyDefinitionCache.values();
}
@Override
public boolean isPropertyDefined(String propertyName) {
return propertyDefinitionCache.containsKey(propertyName);
}
public void ensurePropertyDefined(String name, Object value) {
PropertyDefinition propertyDefinition = getPropertyDefinition(name);
if (propertyDefinition != null) {
return;
}
Class<?> valueClass = getValueType(value);
if (strictTyping) {
throw new VertexiumTypeException(name, valueClass);
}
LOGGER.warn("creating default property definition because a previous definition could not be found for property \"" + name + "\" of type " + valueClass);
propertyDefinition = new PropertyDefinition(name, valueClass, TextIndexHint.ALL);
savePropertyDefinition(propertyDefinition);
}
protected Class<?> getValueType(Object value) {
Class<?> valueClass = value.getClass();
if (value instanceof StreamingPropertyValue) {
valueClass = ((StreamingPropertyValue) value).getValueType();
} else if (value instanceof StreamingPropertyValueRef) {
valueClass = ((StreamingPropertyValueRef) value).getValueType();
}
return valueClass;
}
@Override
public Iterable<Element> saveElementMutations(Iterable<ElementMutation> mutations, Authorizations authorizations) {
List<Element> elements = new ArrayList<>();
for (ElementMutation m : mutations) {
if (m instanceof ExistingElementMutation && !m.hasChanges()) {
elements.add(((ExistingElementMutation) m).getElement());
continue;
}
Element element = m.save(authorizations);
elements.add(element);
}
return elements;
}
@Override
public List<InputStream> getStreamingPropertyValueInputStreams(List<StreamingPropertyValue> streamingPropertyValues) {
return streamingPropertyValues.stream()
.map(StreamingPropertyValue::getInputStream)
.collect(Collectors.toList());
}
@Override
public Iterable<ExtendedDataRow> getExtendedData(Iterable<ExtendedDataRowId> idsIterable, Authorizations authorizations) {
Set<ExtendedDataRowId> ids = Sets.newHashSet(idsIterable);
return new FilterIterable<ExtendedDataRow>(getAllExtendedData(authorizations)) {
@Override
protected boolean isIncluded(ExtendedDataRow row) {
return ids.contains(row.getId());
}
};
}
@Override
public Iterable<ExtendedDataRow> getExtendedData(
ElementType elementType,
String elementId,
String tableName,
Authorizations authorizations
) {
return new FilterIterable<ExtendedDataRow>(getAllExtendedData(authorizations)) {
@Override
protected boolean isIncluded(ExtendedDataRow row) {
ExtendedDataRowId rowId = row.getId();
return (elementType != null && elementType.equals(rowId.getElementType()))
&& (elementId != null && elementId.equals(rowId.getElementId()))
&& (tableName != null && tableName.equals(rowId.getTableName()));
}
};
}
protected Iterable<ExtendedDataRow> getAllExtendedData(Authorizations authorizations) {
JoinIterable<Element> allElements = new JoinIterable<>(getVertices(authorizations), getEdges(authorizations));
return new SelectManyIterable<Element, ExtendedDataRow>(allElements) {
@Override
protected Iterable<? extends ExtendedDataRow> getIterable(Element element) {
return new SelectManyIterable<String, ExtendedDataRow>(element.getExtendedDataTableNames()) {
@Override
protected Iterable<? extends ExtendedDataRow> getIterable(String tableName) {
return element.getExtendedData(tableName);
}
};
}
};
}
protected void deleteAllExtendedDataForElement(Element element, Authorizations authorizations) {
if (element.getExtendedDataTableNames().size() <= 0) {
return;
}
for (ExtendedDataRow row : getExtendedData(ElementType.getTypeFromElement(element), element.getId(), null, authorizations)) {
deleteExtendedDataRow(row.getId(), authorizations);
}
}
}