diff --git a/build.sbt b/build.sbt index 25a2730..f58c58d 100644 --- a/build.sbt +++ b/build.sbt @@ -7,6 +7,10 @@ bucketSuffix := "era7.com" javaVersion := "1.8" libraryDependencies ++= Seq( - "bio4j" % "angulillos" % "0.6.0", + "bio4j" % "angulillos" % "0.7.0", "com.thinkaurelius.titan" % "titan-core" % "1.0.0" ) + +excludeFilter in unmanagedSources := + (excludeFilter in unmanagedSources).value || + "*Index.java" diff --git a/src/main/java/com/bio4j/angulillos/titan/TitanConversions.java b/src/main/java/com/bio4j/angulillos/titan/TitanConversions.java new file mode 100644 index 0000000..42d7bdd --- /dev/null +++ b/src/main/java/com/bio4j/angulillos/titan/TitanConversions.java @@ -0,0 +1,89 @@ +package com.bio4j.angulillos.titan; + +import com.bio4j.angulillos.QueryPredicate; +import com.bio4j.angulillos.Arity; + +import com.thinkaurelius.titan.core.attribute.Cmp; +import com.thinkaurelius.titan.core.attribute.Contain; +import com.thinkaurelius.titan.core.Multiplicity; +import com.thinkaurelius.titan.core.Cardinality; + + +public final class TitanConversions { + + public static final class Predicate { + + public static final Cmp asTitanCmp(QueryPredicate.Compare predicate) { + switch(predicate) { + case EQUAL: return Cmp.EQUAL; + case NOT_EQUAL: return Cmp.NOT_EQUAL; + case GREATER_THAN: return Cmp.GREATER_THAN; + case GREATER_THAN_EQUAL: return Cmp.GREATER_THAN_EQUAL; + case LESS_THAN: return Cmp.LESS_THAN; + case LESS_THAN_EQUAL: return Cmp.LESS_THAN_EQUAL; + // NOTE: this shouldn't happen, because we pattern match on all cases of a sealed enum + default: return Cmp.EQUAL; + } + } + + public static final Contain asTitanContain(QueryPredicate.Contain predicate) { + switch(predicate) { + case IN: return Contain.IN; + case NOT_IN: return Contain.NOT_IN; + // NOTE: this shouldn't happen, because we pattern match on all cases of a sealed enum + default: return Contain.IN; + } + } + + } + + public static final class Arities { + // One/AtMostOne -> ONE + // AtLeastOne/Any -> MANY + // default case represents arity Any + + // NOTE: we don't support non-single cardinality in the angulillos API + // public static final Cardinality asTitanCardinality(Arity arity) { + // switch(arity) { + // case One: return Cardinality.SINGLE; + // case AtMostOne: return Cardinality.SINGLE; + // default: return Cardinality.LIST; + // } + // } + + public static final Multiplicity asTitanMultiplicity(Arity fromArity, Arity toArity) { + switch(fromArity) { + + case One: switch (toArity) { + case One: return Multiplicity.ONE2ONE; + case AtMostOne: return Multiplicity.ONE2ONE; + case AtLeastOne: return Multiplicity.ONE2MANY; + default: return Multiplicity.ONE2MANY; + } + + case AtMostOne: switch (toArity) { + case One: return Multiplicity.ONE2ONE; + case AtMostOne: return Multiplicity.ONE2ONE; + case AtLeastOne: return Multiplicity.ONE2MANY; + default: return Multiplicity.ONE2MANY; + } + + case AtLeastOne: switch (toArity) { + case One: return Multiplicity.MANY2ONE; + case AtMostOne: return Multiplicity.MANY2ONE; + case AtLeastOne: return Multiplicity.MULTI; + default: return Multiplicity.MULTI; + } + + default: switch(toArity) { + case One: return Multiplicity.MANY2ONE; + case AtMostOne: return Multiplicity.MANY2ONE; + case AtLeastOne: return Multiplicity.MULTI; + default: return Multiplicity.MULTI; + } + } + } + + } + +} diff --git a/src/main/java/com/bio4j/angulillos/titan/TitanPredicatesConversion.java b/src/main/java/com/bio4j/angulillos/titan/TitanPredicatesConversion.java deleted file mode 100644 index a5a94c9..0000000 --- a/src/main/java/com/bio4j/angulillos/titan/TitanPredicatesConversion.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bio4j.angulillos.titan; - -import com.bio4j.angulillos.QueryPredicate; - -import com.thinkaurelius.titan.core.attribute.Cmp; -import com.thinkaurelius.titan.core.attribute.Contain; - - -public class TitanPredicatesConversion { - - public static Cmp toTitanCmp(QueryPredicate.Compare predicate) { - switch(predicate) { - case EQUAL: return Cmp.EQUAL; - case NOT_EQUAL: return Cmp.NOT_EQUAL; - case GREATER_THAN: return Cmp.GREATER_THAN; - case GREATER_THAN_EQUAL: return Cmp.GREATER_THAN_EQUAL; - case LESS_THAN: return Cmp.LESS_THAN; - case LESS_THAN_EQUAL: return Cmp.LESS_THAN_EQUAL; - // NOTE: this shouldn't happen, because we pattern match on all cases of a sealed enum - default: return Cmp.EQUAL; - } - } - - public static Contain toTitanContain(QueryPredicate.Contain predicate) { - switch(predicate) { - case IN: return Contain.IN; - case NOT_IN: return Contain.NOT_IN; - // NOTE: this shouldn't happen, because we pattern match on all cases of a sealed enum - default: return Contain.IN; - } - } -} diff --git a/src/main/java/com/bio4j/angulillos/titan/TitanUntypedGraph.java b/src/main/java/com/bio4j/angulillos/titan/TitanUntypedGraph.java index b8f5e69..f7d7821 100644 --- a/src/main/java/com/bio4j/angulillos/titan/TitanUntypedGraph.java +++ b/src/main/java/com/bio4j/angulillos/titan/TitanUntypedGraph.java @@ -10,358 +10,120 @@ import org.apache.tinkerpop.gremlin.structure.Direction; import java.util.stream.Stream; +import java.util.Optional; -public interface TitanUntypedGraph extends UntypedGraph { +public class TitanUntypedGraph +implements + UntypedGraph +{ + private final TitanGraph titanGraph; + public final TitanGraph titanGraph() { return this.titanGraph; } + public TitanUntypedGraph(TitanGraph titanGraph) { this.titanGraph = titanGraph; } - TitanGraph titanGraph(); - default TitanManagement managementSystem() { return titanGraph().openManagement(); } + public TitanManagement managementSystem() { return titanGraph().openManagement(); } - default void commit() { titanGraph().tx().commit(); } - - default void shutdown() { titanGraph().close(); } + @Override + public void commit() { titanGraph().tx().commit(); } @Override - default TitanEdge addEdge(TitanVertex from, EdgeLabelMaker edgeType, TitanVertex to) { + public void shutdown() { titanGraph().close(); } - return from.addEdge( edgeType.getName(), to ); + @Override + public void rollback() { + // titanGraph().rollback(); } + @Override - default TitanVertex addVertex(VertexLabelMaker type) { + public TitanEdge addEdge(TitanVertex source, AnyEdgeType edgeType, TitanVertex target) { - return (TitanVertex) titanGraph().addVertex(type.getName()); + return source.addEdge( edgeType._label(), target ); } @Override - default V getPropertyV(TitanVertex vertex, String property) { + public TitanVertex addVertex(AnyVertexType vertexType) { - return vertex.property(property).value(); + return titanGraph().addVertex(vertexType._label()); } @Override - default void setPropertyV(TitanVertex vertex, String property, V value) { + public V getPropertyV(TitanVertex vertex, AnyProperty property) { - vertex.property(property, value); + return vertex.property(property._label()).value(); } @Override - default V getPropertyE(TitanEdge edge, String property) { + public TitanVertex setPropertyV(TitanVertex vertex, AnyProperty property, V value) { - return edge.property(property).value(); + vertex.property(property._label(), value); + return vertex; } @Override - default void setPropertyE(TitanEdge edge, String property, V value) { + public V getPropertyE(TitanEdge edge, AnyProperty property) { - edge.property(property, value); + return edge.property(property._label()).value(); } @Override - default TitanVertex source(TitanEdge edge) { + public TitanEdge setPropertyE(TitanEdge edge, AnyProperty property, V value) { - return edge.outVertex(); + edge.property(property._label(), value); + return edge; } @Override - default TitanVertex target(TitanEdge edge) { + public TitanVertex source(TitanEdge edge) { return edge.outVertex(); } - return edge.inVertex(); - } + @Override + public TitanVertex target(TitanEdge edge) { return edge.inVertex(); } @Override - default Stream outE(TitanVertex vertex, EdgeLabelMaker edgeType) { + public Stream outE(TitanVertex vertex, AnyEdgeType edgeType) { return stream( vertex.query() - .labels(edgeType.getName()) + .labels(edgeType._label()) .direction(Direction.OUT) .edges() ); } @Override - default Stream outV(TitanVertex vertex, EdgeLabelMaker edgeType) { + public Stream outV(TitanVertex vertex, AnyEdgeType edgeType) { return stream( vertex.query() - .labels(edgeType.getName()) + .labels(edgeType._label()) .direction(Direction.OUT) .vertices() ); } @Override - default Stream inE(TitanVertex vertex, EdgeLabelMaker edgeType) { + public Stream inE(TitanVertex vertex, AnyEdgeType edgeType) { return stream( vertex.query() - .labels(edgeType.getName()) + .labels(edgeType._label()) .direction(Direction.IN) .edges() ); } @Override - default Stream inV(TitanVertex vertex, EdgeLabelMaker edgeType) { + public Stream inV(TitanVertex vertex, AnyEdgeType edgeType) { return stream( vertex.query() - .labels(edgeType.getName()) + .labels(edgeType._label()) .direction(Direction.IN) .vertices() ); } - - /* - creates a key in the graph using the provided `KeyMaker` and `name` if there is no such `PropertyKey` with that `name`; otherwise it returns the existing `PropertyKey` with the provided `name`. - - The `TitanManagement` argument should be the one that was used to create `labelMaker`. - */ - default VertexLabel createOrGet(TitanManagement mgmt, VertexLabelMaker labelMaker) { - - VertexLabel vertexLabel; - String name = labelMaker.getName(); - - if ( mgmt.containsVertexLabel(name) ) { - - vertexLabel = mgmt.getVertexLabel(name); - } - else { - - vertexLabel = labelMaker.make(); - } - - return vertexLabel; - } - - /* - creates a label in the graph using the provided `LabelMaker` and `name` if there is no such `EdgeLabel` with that `name`; otherwise it returns the existing `EdgeLabel` with the provided `name`. - */ - default EdgeLabel createOrGet(TitanManagement mgmt, EdgeLabelMaker labelMaker) { - - EdgeLabel edgeLabel; - String name = labelMaker.getName(); - - if ( mgmt.containsEdgeLabel(name) ) { - - edgeLabel = mgmt.getEdgeLabel(name); - } - else { - - edgeLabel = labelMaker.make(); - } - - return edgeLabel; - } - - default PropertyKey createOrGet(TitanManagement mgmt, PropertyKeyMaker propertyMaker) { - - PropertyKey propertyKey; - String name = propertyMaker.getName(); - - if ( mgmt.containsPropertyKey(name) ) { - - propertyKey = mgmt.getPropertyKey(name); - } - else { - - propertyKey = propertyMaker.make(); - } - - return propertyKey; - } - - - - /* - Get a `VertexLabelMaker` for a vertex type - */ - default < - N extends TypedVertex, - NT extends TypedVertex.Type, - G extends TypedGraph, - I extends TitanUntypedGraph - > - VertexLabelMaker titanLabelMakerForVertexType(TitanManagement mgmt, NT vertexType) { - - // TODO: evaluate partition() and setStatic() - return mgmt.makeVertexLabel(vertexType.name()); - } - - /* - Create a `LabelMaker` with the minimum defaults (name, arity and directed) for an edge type. As this is a `LabelMaker`, you can further refine it and define its signature, indexing etc. - */ - default < - // src - S extends TypedVertex, - ST extends TypedVertex.Type, - SG extends TypedGraph, - // edge - R extends TypedEdge, - RT extends TypedEdge.Type, - G extends TypedGraph, - I extends TitanUntypedGraph, - //tgt - T extends TypedVertex, - TT extends TypedVertex.Type, - TG extends TypedGraph - > - EdgeLabelMaker titanLabelMakerForEdgeType(TitanManagement mgmt, RT relationshipType) { - - EdgeLabelMaker labelMaker = mgmt.makeEdgeLabel(relationshipType.name()).directed(); - - // set the arity - // one/atMostOne -> ONE - // atLeastOne/any -> MANY - switch (relationshipType.arity()) { - - case oneToOne: labelMaker.multiplicity(Multiplicity.ONE2ONE); break; - case oneToAtMostOne: labelMaker.multiplicity(Multiplicity.ONE2ONE); break; - case oneToAtLeastOne: labelMaker.multiplicity(Multiplicity.ONE2MANY); break; - case oneToAny: labelMaker.multiplicity(Multiplicity.ONE2MANY); break; - - case atMostOneToOne: labelMaker.multiplicity(Multiplicity.ONE2ONE); break; - case atMostOneToAtMostOne: labelMaker.multiplicity(Multiplicity.ONE2ONE); break; - case atMostOneToAtLeastOne: labelMaker.multiplicity(Multiplicity.ONE2MANY); break; - case atMostOneToAny: labelMaker.multiplicity(Multiplicity.ONE2MANY); break; - - case atLeastOneToOne: labelMaker.multiplicity(Multiplicity.MANY2ONE); break; - case atLeastOneToAtMostOne: labelMaker.multiplicity(Multiplicity.MANY2ONE); break; - case atLeastOneToAtLeastOne: labelMaker.multiplicity(Multiplicity.MULTI); break; - case atLeastOneToAny: labelMaker.multiplicity(Multiplicity.MULTI); break; - - case anyToOne: labelMaker.multiplicity(Multiplicity.MANY2ONE); break; - case anyToAtMostOne: labelMaker.multiplicity(Multiplicity.MANY2ONE); break; - case anyToAtLeastOne: labelMaker.multiplicity(Multiplicity.MULTI); break; - case anyToAny: labelMaker.multiplicity(Multiplicity.MULTI); break; - - default: labelMaker.multiplicity(Multiplicity.MULTI); - } - - return labelMaker; - } - - // see http://s3.thinkaurelius.com/docs/titan/0.5.1/data-model.html#_individual_edge_layout for why you might want this - default < - // src - S extends TypedVertex, - ST extends TypedVertex.Type, - SG extends TypedGraph, - // edge - R extends TypedEdge, - // graph - RT extends TypedEdge.Type, - G extends TypedGraph, - I extends TitanUntypedGraph, - //tgt - T extends TypedVertex, - TT extends TypedVertex.Type, - TG extends TypedGraph - > - EdgeLabelMaker titanLabelMakerForEdgeTypeWithProperties(TitanManagement mgmt, RT edgeType, PropertyKey... propertyKeys) { - - return titanLabelMakerForEdgeType(mgmt, edgeType).signature(propertyKeys); - } - - /* - create an `EdgeLabel` for an type, using the default configuration. If a type with the same name is present it will be returned instead. - */ - default < - // src - S extends TypedVertex, - ST extends TypedVertex.Type, - SG extends TypedGraph, - // edge - R extends TypedEdge, - RT extends TypedEdge.Type, - G extends TypedGraph, - I extends TitanUntypedGraph, - //tgt - T extends TypedVertex, - TT extends TypedVertex.Type, - TG extends TypedGraph - > - EdgeLabel titanLabelForEdgeType(TitanManagement mgmt, RT relationshipType) { - - // TODO: check that arities etc are ok, throw if not - return createOrGet(mgmt, titanLabelMakerForEdgeType(mgmt, relationshipType)); - } - - - default < - N extends TypedVertex, - NT extends TypedVertex.Type, - P extends Property, V, - G extends TypedGraph, - I extends TitanUntypedGraph - > - PropertyKeyMaker titanPropertyMakerForVertexProperty(TitanManagement mgmt, P property) { - - return mgmt.makePropertyKey(property.name()).dataType(property.valueClass()); - } - - default < - // src - S extends TypedVertex, - ST extends TypedVertex.Type, - SG extends TypedGraph, - // edge - R extends TypedEdge, - RT extends TypedEdge.Type, - // property - P extends Property, V, - // graph - G extends TypedGraph, I extends TitanUntypedGraph, - //tgt - T extends TypedVertex, - TT extends TypedVertex.Type, - TG extends TypedGraph - > - PropertyKeyMaker titanPropertyMakerForEdgeProperty(TitanManagement mgmt, P property) { - - return mgmt.makePropertyKey(property.name()).dataType(property.valueClass()); - } - - // default < - // // src - // S extends TypedVertex, - // ST extends TypedVertex.Type, - // SG extends TypedGraph, - // // edge - // R extends TypedEdge, - // RT extends TypedEdge.Type, - // // property - // P extends Property, V, - // // graph - // G extends TypedGraph, I extends TitanUntypedGraph, - // //tgt - // T extends TypedVertex, - // TT extends TypedVertex.Type, - // TG extends TypedGraph - // > - // PropertyKey titanKeyForEdgePropertySingle(P property) { - - // return createOrGet(titanKeyMakerForEdgeProperty(property).single(), property.name()); - // } - - // /* - // create a `PropertyKey` for a single vertex property, using the default configuration. If a property with the same name is present it will be returned instead. - // */ - // default < - // N extends TypedVertex, - // NT extends TypedVertex.Type, - // P extends Property, V, - // G extends TypedGraph, - // I extends TitanUntypedGraph - // > - // PropertyKey titanKeyForVertexPropertySingle(P property) { - - // return createOrGet(titanKeyMakerForVertexProperty(property).single(), property.name()); - // } - } diff --git a/src/main/java/com/bio4j/angulillos/titan/TitanUntypedSchemaManager.java b/src/main/java/com/bio4j/angulillos/titan/TitanUntypedSchemaManager.java new file mode 100644 index 0000000..fac09df --- /dev/null +++ b/src/main/java/com/bio4j/angulillos/titan/TitanUntypedSchemaManager.java @@ -0,0 +1,55 @@ +package com.bio4j.angulillos.titan; + +import com.bio4j.angulillos.*; + +import static com.bio4j.angulillos.conversions.*; +import static com.bio4j.angulillos.titan.TitanConversions.*; + +import com.thinkaurelius.titan.core.*; +import com.thinkaurelius.titan.core.schema.*; + +import org.apache.tinkerpop.gremlin.structure.Direction; + + +public class TitanUntypedSchemaManager +implements UntypedGraphSchema { + + // TODO: create if not exists? + + /* This method should take into account vertex label */ + public SchemaManager createVertexType(SchemaManager schemaManager, AnyVertexType vertexType) { + schemaManager + .makeVertexLabel(vertexType._label()) + // .setStatic() ? + .make(); + return schemaManager; + } + + /* This method should take into account edge label, source/target types and to/from-arities */ + public SchemaManager createEdgeType(SchemaManager schemaManager, AnyEdgeType edgeType) { + schemaManager + .makeEdgeLabel(edgeType._label()) + .directed() + .multiplicity( + Arities.asTitanMultiplicity( + edgeType.fromArity(), + edgeType.toArity() + ) + ) + // TODO: for making signature, we have to create all edge's properties beforehand + // .signature(edgeType.properties...) + .make(); + return schemaManager; + } + + /* This method should take into account property's element type and from-arity */ + public SchemaManager createProperty(SchemaManager schemaManager, AnyProperty property) { + schemaManager + .makePropertyKey(property._label()) + .cardinality( Cardinality.SINGLE ) + .dataType( property.valueClass() ) + .make(); + return schemaManager; + } + +}