package org.vertexium.sql; import com.google.common.collect.Iterables; import org.vertexium.*; import org.vertexium.inmemory.*; import org.vertexium.mutation.SetPropertyMetadata; import org.vertexium.property.StreamingPropertyValue; import org.vertexium.property.StreamingPropertyValueRef; import org.vertexium.sql.collections.SqlMap; import org.vertexium.sql.collections.Storable; import org.vertexium.util.ConvertingIterable; import org.vertexium.util.LookAheadIterable; import java.util.*; public class SqlGraph extends InMemoryGraph { private final SqlMap<InMemoryTableElement<InMemoryVertex>> vertexMap; private final SqlMap<InMemoryTableElement<InMemoryEdge>> edgeMap; private final SqlStreamingPropertyTable streamingPropertyTable; private static class ConfigHolder { final SqlGraphConfiguration configuration; final SqlMap<InMemoryTableElement<InMemoryVertex>> vertexMap; final SqlMap<InMemoryTableElement<InMemoryEdge>> edgeMap; final SqlExtendedDataTable extendedDataTable; final SqlStreamingPropertyTable streamingPropertyTable; ConfigHolder(SqlGraphConfiguration configuration) { this.configuration = configuration; this.vertexMap = configuration.newVertexMap(); this.edgeMap = configuration.newEdgeMap(); this.extendedDataTable = configuration.newExtendedDataTable(); this.streamingPropertyTable = configuration.newStreamingPropertyTable(); } } public SqlGraph(SqlGraphConfiguration configuration) { this(new ConfigHolder(configuration)); } private SqlGraph(ConfigHolder configHolder) { super( configHolder.configuration, new SqlVertexTable(configHolder.vertexMap), new SqlEdgeTable(configHolder.edgeMap), configHolder.extendedDataTable ); this.vertexMap = configHolder.vertexMap; this.edgeMap = configHolder.edgeMap; this.streamingPropertyTable = configHolder.streamingPropertyTable; this.vertexMap.setStorableContext(this); this.edgeMap.setStorableContext(this); } @Override protected GraphMetadataStore newGraphMetadataStore(GraphConfiguration configuration) { return new SqlGraphMetadataStore(((SqlGraphConfiguration) configuration).newMetadataMap()); } public static SqlGraph create(SqlGraphConfiguration config) { if (config.isCreateTables()) { SqlGraphDDL.create(config.getDataSource(), config); } SqlGraph graph = new SqlGraph(config); graph.setup(); return graph; } @SuppressWarnings("unused") public static SqlGraph create(Map<String, Object> config) { return create(new SqlGraphConfiguration(config)); } @Override public Vertex getVertex( String vertexId, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations ) { validateAuthorizations(authorizations); InMemoryTableElement<InMemoryVertex> element = vertexMap.get(vertexId); if (element == null || !isIncludedInTimeSpan(element, fetchHints, endTime, authorizations)) { return null; } else { return element.createElement(this, fetchHints, endTime, authorizations); } } @Override public Iterable<Vertex> getVerticesWithPrefix( final String vertexIdPrefix, final EnumSet<FetchHint> fetchHints, final Long endTime, final Authorizations authorizations ) { validateAuthorizations(authorizations); return new LookAheadIterable<InMemoryTableVertex, Vertex>() { @Override protected boolean isIncluded(InMemoryTableVertex element, Vertex vertex) { return vertex != null && SqlGraph.this.isIncluded(element, fetchHints, authorizations); } @Override protected Vertex convert(InMemoryTableVertex element) { return element.createElement(SqlGraph.this, fetchHints, endTime, authorizations); } @Override protected Iterator<InMemoryTableVertex> createIterator() { Iterator<InMemoryTableElement<InMemoryVertex>> elements = vertexMap.query( "id like ?", vertexIdPrefix + "%" ); return new ConvertingIterable<InMemoryTableElement<InMemoryVertex>, InMemoryTableVertex>(elements) { @Override protected InMemoryTableVertex convert(InMemoryTableElement<InMemoryVertex> element) { return ((SqlTableVertex) element).asInMemoryTableElement(); } }.iterator(); } }; } @Override public Edge getEdge(String edgeId, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations) { InMemoryTableElement<InMemoryEdge> element = edgeMap.get(edgeId); if (element == null || !isIncluded(element, fetchHints, authorizations)) { return null; } else { return element.createElement(this, fetchHints, endTime, authorizations); } } @SuppressWarnings("unchecked") @Override public Iterable<Vertex> getVertices( final Iterable<String> ids, final EnumSet<FetchHint> fetchHints, final Long endTime, final Authorizations authorizations ) { return (Iterable<Vertex>) getElements(ids, fetchHints, endTime, authorizations, vertexMap); } @SuppressWarnings("unchecked") @Override public Iterable<Edge> getEdges( Iterable<String> ids, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations ) { return (Iterable<Edge>) getElements(ids, fetchHints, endTime, authorizations, edgeMap); } private <T extends InMemoryElement> Iterable<?> getElements( Iterable<String> ids, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations, SqlMap<InMemoryTableElement<T>> sqlMap ) { return new LookAheadIterable<InMemoryTableElement, T>() { @Override protected boolean isIncluded(InMemoryTableElement srcElement, T destElement) { return destElement != null && SqlGraph.this.isIncluded(srcElement, fetchHints, authorizations); } @SuppressWarnings("unchecked") @Override protected T convert(InMemoryTableElement element) { return (T) element.createElement(SqlGraph.this, fetchHints, endTime, authorizations); } @SuppressWarnings("unused") @Override protected Iterator<InMemoryTableElement> createIterator() { StringBuilder idWhere = new StringBuilder(); boolean first = true; for (String id : ids) { if (first) { idWhere.append("id = ?"); first = false; } else { idWhere.append(" or id = ?"); } } if (first) { return Collections.emptyIterator(); } else { Iterator<InMemoryTableElement<T>> elements = sqlMap.query( idWhere.toString(), Iterables.toArray(ids, Object.class) ); return new ConvertingIterable<InMemoryTableElement, InMemoryTableElement>(elements) { @Override protected InMemoryTableElement convert(InMemoryTableElement element) { return ((SqlTableElement) element).asInMemoryTableElement(); } }.iterator(); } } }; } @Override public Iterable<Edge> getEdgesFromVertex( String vertexId, EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations ) { return new LookAheadIterable<InMemoryTableEdge, Edge>() { @Override protected boolean isIncluded(InMemoryTableEdge element, Edge edge) { return edge != null && SqlGraph.this.isIncluded(element, fetchHints, authorizations); } @Override protected Edge convert(InMemoryTableEdge element) { return element.createElement(SqlGraph.this, fetchHints, endTime, authorizations); } @Override protected Iterator<InMemoryTableEdge> createIterator() { Iterator<InMemoryTableElement<InMemoryEdge>> elements = edgeMap.query("in_vertex_id = ? or out_vertex_id = ?", vertexId, vertexId); return new ConvertingIterable<InMemoryTableElement<InMemoryEdge>, InMemoryTableEdge>(elements) { @Override protected InMemoryTableEdge convert(InMemoryTableElement<InMemoryEdge> element) { return ((SqlTableEdge) element).asInMemoryTableElement(); } }.iterator(); } }; } @Override protected void alterElementPropertyMetadata( InMemoryTableElement inMemoryTableElement, List<SetPropertyMetadata> setPropertyMetadatas, Authorizations authorizations ) { super.alterElementPropertyMetadata(inMemoryTableElement, setPropertyMetadatas, authorizations); ((Storable) inMemoryTableElement).store(); } protected SqlStreamingPropertyTable getStreamingPropertyTable() { return streamingPropertyTable; } @Override protected StreamingPropertyValueRef saveStreamingPropertyValue( String elementId, String key, String name, Visibility visibility, long timestamp, StreamingPropertyValue value ) { return streamingPropertyTable.put(elementId, key, name, visibility, timestamp, value); } }