// Copyright 2017 JanusGraph Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.janusgraph.graphdb.types; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import org.janusgraph.core.*; import org.janusgraph.core.Multiplicity; import org.janusgraph.core.schema.RelationTypeMaker; import org.janusgraph.core.schema.SchemaStatus; import org.janusgraph.graphdb.database.IndexSerializer; import org.janusgraph.graphdb.database.serialize.AttributeHandler; import org.janusgraph.graphdb.internal.Order; import org.janusgraph.graphdb.internal.JanusGraphSchemaCategory; import org.janusgraph.graphdb.transaction.StandardJanusGraphTx; import org.janusgraph.graphdb.types.system.SystemTypeManager; import java.util.*; import static org.janusgraph.graphdb.types.TypeDefinitionCategory.*; public abstract class StandardRelationTypeMaker implements RelationTypeMaker { protected final StandardJanusGraphTx tx; protected final IndexSerializer indexSerializer; protected final AttributeHandler attributeHandler; private String name; private boolean isInvisible; private List<PropertyKey> sortKey; private Order sortOrder; private List<PropertyKey> signature; private Multiplicity multiplicity; private SchemaStatus status = SchemaStatus.ENABLED; public StandardRelationTypeMaker(final StandardJanusGraphTx tx, String name, final IndexSerializer indexSerializer, final AttributeHandler attributeHandler) { Preconditions.checkNotNull(tx); Preconditions.checkNotNull(indexSerializer); Preconditions.checkNotNull(attributeHandler); this.tx = tx; this.indexSerializer = indexSerializer; this.attributeHandler = attributeHandler; name(name); //Default assignments isInvisible = false; sortKey = new ArrayList<>(4); sortOrder = Order.ASC; signature = new ArrayList<>(4); multiplicity = Multiplicity.MULTI; } public String getName() { return this.name; } protected boolean hasSortKey() { return !sortKey.isEmpty(); } protected Multiplicity getMultiplicity() { return multiplicity; } abstract JanusGraphSchemaCategory getSchemaCategory(); private void checkGeneralArguments() { checkSortKey(sortKey); Preconditions.checkArgument(sortOrder==Order.ASC || hasSortKey(),"Must define a sort key to use ordering"); checkSignature(signature); Preconditions.checkArgument(Sets.intersection(Sets.newHashSet(sortKey), Sets.newHashSet(signature)).isEmpty(), "Signature and sort key must be disjoined"); Preconditions.checkArgument(!hasSortKey() || !multiplicity.isConstrained(),"Cannot define a sort-key on constrained edge labels"); } private long[] checkSortKey(List<PropertyKey> sig) { for (PropertyKey key : sig) { Preconditions.checkArgument(attributeHandler.isOrderPreservingDatatype(key.dataType()), "Key must have an order-preserving data type to be used as sort key: " + key); } return checkSignature(sig); } private static long[] checkSignature(List<PropertyKey> sig) { Preconditions.checkArgument(sig.size() == (Sets.newHashSet(sig)).size(), "Signature and sort key cannot contain duplicate types"); long[] signature = new long[sig.size()]; for (int i = 0; i < sig.size(); i++) { PropertyKey key = sig.get(i); Preconditions.checkNotNull(key); Preconditions.checkArgument(!((PropertyKey) key).dataType().equals(Object.class), "Signature and sort keys must have a proper declared datatype: %s", key.name()); signature[i] = key.longId(); } return signature; } protected final TypeDefinitionMap makeDefinition() { checkGeneralArguments(); TypeDefinitionMap def = new TypeDefinitionMap(); def.setValue(INVISIBLE, isInvisible); def.setValue(SORT_KEY, checkSortKey(sortKey)); def.setValue(SORT_ORDER, sortOrder); def.setValue(SIGNATURE, checkSignature(signature)); def.setValue(MULTIPLICITY,multiplicity); def.setValue(STATUS,status); return def; } public StandardRelationTypeMaker multiplicity(Multiplicity multiplicity) { Preconditions.checkNotNull(multiplicity); this.multiplicity=multiplicity; return this; } @Override public StandardRelationTypeMaker signature(PropertyKey... types) { Preconditions.checkArgument(types!=null && types.length>0); signature.addAll(Arrays.asList(types)); return this; } public StandardRelationTypeMaker status(SchemaStatus status) { Preconditions.checkArgument(status!=null); this.status=status; return this; } /** * Configures the composite sort key for this label. * <p/> * Specifying the sort key of a type allows relations of this type to be efficiently retrieved in the order of * the sort key. * <br /> * For instance, if the edge label <i>friend</i> has the sort key (<i>since</i>), which is a property key * with a timestamp data type, then one can efficiently retrieve all edges with label <i>friend</i> in a specified * time interval using {@link org.janusgraph.core.JanusGraphVertexQuery#interval(org.janusgraph.core.PropertyKey, Comparable, Comparable)}. * <br /> * In other words, relations are stored on disk in the order of the configured sort key. The sort key is empty * by default. * <br /> * If multiple types are specified as sort key, then those are considered as a <i>composite</i> sort key, i.e. taken jointly * in the given order. * <p/> * {@link org.janusgraph.core.RelationType}s used in the sort key must be either property out-unique keys or out-unique unidirected edge lables. * * @param keys JanusGraphTypes composing the sort key. The order is relevant. * @return this LabelMaker */ public StandardRelationTypeMaker sortKey(PropertyKey... keys) { Preconditions.checkArgument(keys!=null && keys.length>0); sortKey.addAll(Arrays.asList(keys)); return this; } /** * Defines in which order to sort the relations for efficient retrieval, i.e. either increasing ({@link org.janusgraph.graphdb.internal.Order#ASC}) or * decreasing ({@link org.janusgraph.graphdb.internal.Order#DESC}). * * Note, that only one sort order can be specified and that a sort key must be defined to use a sort order. * * @param order * @return * @see #sortKey(RelationType...) */ public StandardRelationTypeMaker sortOrder(Order order) { Preconditions.checkNotNull(order); this.sortOrder=order; return this; } public StandardRelationTypeMaker name(String name) { SystemTypeManager.isNotSystemName(getSchemaCategory(), name); this.name = name; return this; } public StandardRelationTypeMaker invisible() { this.isInvisible = true; return this; } }