/** * Thrown when changing the super of a {@link Type} will result in a {@link Role} disconnection which is in use. */ public static GraknTxOperationException changingSuperWillDisconnectRole(Type oldSuper, Type newSuper, Role role){ return create(String.format("Cannot change the super type {%s} to {%s} because {%s} is connected to role {%s} which {%s} is not connected to.", oldSuper.label(), newSuper.label(), oldSuper.label(), role.label(), newSuper.label())); }
/** * Add is-abstract annotation to a var * @param var var to be marked * @param type type from which metadata extracted */ private static VarPattern isAbstract(VarPattern var, Type type) { return type.isAbstract() ? var.isAbstract() : var; }
public void removeFromValidation(Type type){ if (type.isRelationshipType()) { modifiedRelationshipTypes.remove(type.asRelationshipType()); } }
private Thing putInstance() { Type type = use(TYPE); if (type.isEntityType()) { return type.asEntityType().create(); } else if (type.isRelationshipType()) { return type.asRelationshipType().create(); } else if (type.isAttributeType()) { return type.asAttributeType().create(use(VALUE)); } else if (type.label().equals(Schema.MetaSchema.THING.getLabel())) { throw GraqlQueryException.createInstanceOfMetaConcept(var, type); } else { throw CommonUtil.unreachableStatement("Can't recognize type " + type); } }
/** * This is a temporary patch to prevent accidentally disconnecting implicit {@link RelationshipType}s from their * {@link RelationshipEdge}s. This Disconnection happens because {@link RelationshipType#instances()} depends on the * presence of a direct {@link Schema.EdgeLabel#PLAYS} edge between the {@link Type} and the implicit {@link RelationshipType}. * * When changing the super you may accidentally cause this disconnection. So we prevent it here. * */ //TODO: Remove this when traversing to the instances of an implicit Relationship Type is no longer done via plays edges @Override boolean changingSuperAllowed(T oldSuperType, T newSuperType){ boolean changingSuperAllowed = super.changingSuperAllowed(oldSuperType, newSuperType); if(changingSuperAllowed && oldSuperType != null && !Schema.MetaSchema.isMetaLabel(oldSuperType.label())) { //noinspection unchecked Set<Role> superPlays = oldSuperType.playing().collect(Collectors.toSet()); //Get everything that this can play bot including the supers Set<Role> plays = new HashSet<>(directPlays().keySet()); subs().flatMap(sub -> TypeImpl.from(sub).directPlays().keySet().stream()).forEach(plays::add); superPlays.removeAll(plays); //It is possible to be disconnecting from a role which is no longer in use but checking this will take too long //So we assume the role is in sure and throw if that is the case if(!superPlays.isEmpty() && instancesDirect().findAny().isPresent()){ throw GraknTxOperationException.changingSuperWillDisconnectRole(oldSuperType, newSuperType, superPlays.iterator().next()); } return true; } return changingSuperAllowed; }
/** * @param typedVar variable of interest * @param parentType to be checked * @return true if typing the typeVar with type is compatible with role configuration of this query */ @Override public boolean isTypeRoleCompatible(Var typedVar, Type parentType){ if (parentType == null || Schema.MetaSchema.isMetaLabel(parentType.label())) return true; Set<Type> parentTypes = parentType.subs().collect(Collectors.toSet()); return getAtoms(RelationshipAtom.class) .filter(ra -> ra.getVarNames().contains(typedVar)) .noneMatch(ra -> ra.getRoleVarMap().entries().stream() //get roles this type needs to play .filter(e -> e.getValue().equals(typedVar)) .filter(e -> !Schema.MetaSchema.isMetaLabel(e.getKey().label())) //check if it can play it .anyMatch(e -> e.getKey().players().noneMatch(parentTypes::contains))); }
@Override public Stream<Role> toCompatibleRoles(Type entryType) { return entryType.subs().flatMap(Type::playing); } }
/** * Helper method to validate that the target types are of one data type, and get that data type * * @return the DataType of the target types */ @Nullable private AttributeType.DataType<?> validateAndGetTargetDataType() { AttributeType.DataType<?> dataType = null; for (Type type : targetTypes()) { // check if the selected type is a attribute type if (!type.isAttributeType()) throw GraqlQueryException.mustBeAttributeType(type.label()); AttributeType<?> attributeType = type.asAttributeType(); if (dataType == null) { // check if the attribute type has data-type LONG or DOUBLE dataType = attributeType.dataType(); if (!dataType.equals(AttributeType.DataType.LONG) && !dataType.equals(AttributeType.DataType.DOUBLE)) { throw GraqlQueryException.attributeMustBeANumber(dataType, attributeType.label()); } } else { // check if all the attribute types have the same data-type if (!dataType.equals(attributeType.dataType())) { throw GraqlQueryException.attributesWithDifferentDataTypes(query.of().get()); } } } return dataType; }
/** * Helper method to get the types to be included in the query target * * @return a set of Types */ private ImmutableSet<Type> targetTypes() { if (!query.of().isPresent() || query.of().get().isEmpty()) { throw GraqlQueryException.statisticsAttributeTypesNotSpecified(); } return query.of().get().stream() .map((label) -> { Type type = tx.getSchemaConcept(label); if (type == null) throw GraqlQueryException.labelNotFound(label); if (!type.isAttributeType()) throw GraqlQueryException.mustBeAttributeType(type.label()); return type; }) .flatMap(Type::subs) .collect(CommonUtil.toImmutableSet()); }
@Override public Set<String> validateOntologically() { SchemaConcept type = getSchemaConcept(); Set<String> errors = new HashSet<>(); if (type == null) return errors; if (!type.isAttributeType()){ errors.add(ErrorMessage.VALIDATION_RULE_INVALID_ATTRIBUTE_TYPE.getMessage(type.label())); return errors; } Type ownerType = getParentQuery().getVarTypeMap().get(getVarName()); if (ownerType != null && ownerType.attributes().noneMatch(rt -> rt.equals(type.asAttributeType()))){ errors.add(ErrorMessage.VALIDATION_RULE_ATTRIBUTE_OWNER_CANNOT_HAVE_ATTRIBUTE.getMessage(type.label(), ownerType.label())); } return errors; }
Label label = relationshipType.label(); IsaProperty isaProperty = IsaProperty.of(labelVar.admin()); EquivalentFragmentSet isaEquivalentFragmentSet = EquivalentFragmentSets.isa(isaProperty, relationshipVar, labelVar, relationshipType.isImplicit()); allFragments.addAll(isaEquivalentFragmentSet.fragments());
Type type = tx.getSchemaConcept(typeLabel); if (type == null) throw GraqlQueryException.labelNotFound(typeLabel); if (type.isRelationshipType()) throw GraqlQueryException.kCoreOnRelationshipType(typeLabel); return type.subs(); }) .map(SchemaConcept::label)
@Override public Collection<PropertyExecutor> undefine(Var var) throws GraqlQueryException { PropertyExecutor.Method method = executor -> { Type type = executor.get(var).asType(); if (!type.isDeleted()) { type.isAbstract(false); } }; return ImmutableSet.of(PropertyExecutor.builder(method).requires(var).build()); }
/** * Helper method to get the types to be included in the query scope * * @return stream of Concept Types */ private Stream<Type> scopeTypes() { // Get all types if query.inTypes() is empty, else get all scoped types of each meta type. // Only include attributes and implicit "has-xxx" relationships when user specifically asked for them. if (!query.in().isPresent() || query.in().get().isEmpty()) { ImmutableSet.Builder<Type> typeBuilder = ImmutableSet.builder(); if (scopeIncludesAttributes()) { tx.admin().getMetaConcept().subs().forEach(typeBuilder::add); } else { tx.admin().getMetaEntityType().subs().forEach(typeBuilder::add); tx.admin().getMetaRelationType().subs() .filter(relationshipType -> !relationshipType.isImplicit()).forEach(typeBuilder::add); } return typeBuilder.build().stream(); } else { Stream<Type> subTypes = query.in().get().stream().map(label -> { Type type = tx.getType(label); if (type == null) throw GraqlQueryException.labelNotFound(label); return type; }).flatMap(Type::subs); if (!scopeIncludesAttributes()) { subTypes = subTypes.filter(relationshipType -> !relationshipType.isImplicit()); } return subTypes; } }
@Override public Collection<PropertyExecutor> define(Var var) throws GraqlQueryException { PropertyExecutor.Method method = executor -> { Type entityTypeConcept = executor.get(var).asType(); AttributeType attributeTypeConcept = executor.get(resourceType().var()).asAttributeType(); if (required()) { entityTypeConcept.key(attributeTypeConcept); } else { entityTypeConcept.has(attributeTypeConcept); } }; return ImmutableSet.of(PropertyExecutor.builder(method).requires(var, resourceType().var()).build()); }
private Relationship attributeRelationship(Attribute attribute, boolean isInferred) { Schema.ImplicitType has = Schema.ImplicitType.HAS; Schema.ImplicitType hasValue = Schema.ImplicitType.HAS_VALUE; Schema.ImplicitType hasOwner = Schema.ImplicitType.HAS_OWNER; //Is this attribute a key to me? if(type().keys().anyMatch(rt -> rt.equals(attribute.type()))){ has = Schema.ImplicitType.KEY; hasValue = Schema.ImplicitType.KEY_VALUE; hasOwner = Schema.ImplicitType.KEY_OWNER; } Label label = attribute.type().label(); RelationshipType hasAttribute = vertex().tx().getSchemaConcept(has.getLabel(label)); Role hasAttributeOwner = vertex().tx().getSchemaConcept(hasOwner.getLabel(label)); Role hasAttributeValue = vertex().tx().getSchemaConcept(hasValue.getLabel(label)); if(hasAttribute == null || hasAttributeOwner == null || hasAttributeValue == null || type().playing().noneMatch(play -> play.equals(hasAttributeOwner))){ throw GraknTxOperationException.hasNotAllowed(this, attribute); } EdgeElement attributeEdge = addEdge(AttributeImpl.from(attribute), Schema.EdgeLabel.ATTRIBUTE); if(isInferred) attributeEdge.property(Schema.EdgeProperty.IS_INFERRED, true); return vertex().tx().factory().buildRelation(attributeEdge, hasAttribute, hasAttributeOwner, hasAttributeValue); }
/** * Add plays edges to a var, given a type * @param var var to be modified * @param type type from which metadata extracted * @return var with appropriate plays edges */ private static VarPattern plays(VarPattern var, Type type) { for(Role role:type.playing().collect(Collectors.toSet())){ var = var.plays(Graql.label(role.label())); } return var; }
@Override protected final T generateFromTx() { T thing; S type = genFromTx(generatorClass).makeExcludeAbstractTypes().excludeMeta().generate(random, status); //noinspection unchecked Collection<T> instances = (Collection<T> ) type.instances().collect(toSet()); if (instances.isEmpty()) { thing = newInstance(type); } else { thing = random.choose(instances); } if(withResource && !thing.attributes().findAny().isPresent()){ //A new attribute type is created every time a attribute is lacking. //Existing attribute types and resources of those types are not used because we end up mutating the // the schema in strange ways. This approach is less complex but ensures everything has a attribute // without conflicting with the schema //Create a new attribute type AttributeType.DataType<?> dataType = gen(AttributeType.DataType.class); Label label = genFromTx(Labels.class).mustBeUnused().generate(random, status); AttributeType attributeType = tx().putAttributeType(label, dataType); //Create new attribute Attribute attribute = newResource(attributeType); //Link everything together type.has(attributeType); thing.has(attribute); } return thing; }