/** * @param schemaConcepts entry {@link SchemaConcept} set * @return top {@link SchemaConcept}s from within the provided set or meta concept if it exists */ public static <T extends SchemaConcept> Set<T> topOrMeta(Set<T> schemaConcepts) { Set<T> concepts = top(schemaConcepts); T meta = concepts.stream() .filter(c -> Schema.MetaSchema.isMetaLabel(c.label())) .findFirst().orElse(null); return meta != null ? Collections.singleton(meta) : concepts; }
/** * @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))); }
/** * @return a map of relationships and corresponding roles that could be played by this atom */ private Multimap<RelationshipType, Role> inferPossibleRelationConfigurations(ConceptMap sub){ Set<Role> roles = getExplicitRoles().filter(r -> !Schema.MetaSchema.isMetaLabel(r.label())).collect(toSet()); Map<Var, Type> varTypeMap = getParentQuery().getVarTypeMap(sub); Set<Type> types = getRolePlayers().stream().filter(varTypeMap::containsKey).map(varTypeMap::get).collect(toSet()); if (roles.isEmpty() && types.isEmpty()){ RelationshipType metaRelationType = tx().admin().getMetaRelationType(); Multimap<RelationshipType, Role> compatibleTypes = HashMultimap.create(); metaRelationType.subs() .filter(rt -> !rt.equals(metaRelationType)) .forEach(rt -> compatibleTypes.putAll(rt, rt.roles().collect(toSet()))); return compatibleTypes; } //intersect relation types from roles and types Multimap<RelationshipType, Role> compatibleTypes; Multimap<RelationshipType, Role> compatibleTypesFromRoles = compatibleRelationTypesWithRoles(roles, new RoleConverter()); Multimap<RelationshipType, Role> compatibleTypesFromTypes = compatibleRelationTypesWithRoles(types, new TypeConverter()); if (roles.isEmpty()){ compatibleTypes = compatibleTypesFromTypes; } //no types from roles -> roles correspond to mutually exclusive relations else if(compatibleTypesFromRoles.isEmpty() || types.isEmpty()){ compatibleTypes = compatibleTypesFromRoles; } else { compatibleTypes = multimapIntersection(compatibleTypesFromTypes, compatibleTypesFromRoles); } return compatibleTypes; }
boolean allRolesMeta = explicitRoles.stream().allMatch(role -> Schema.MetaSchema.isMetaLabel(role.label())); boolean roleRecomputationViable = allRolesMeta && (!sub.isEmpty() || !Sets.intersection(varTypeMap.keySet(), getRolePlayers()).isEmpty()); if (explicitRoles.size() == getRelationPlayers().size() && !roleRecomputationViable) return this; Label roleLabel = rolePattern.getTypeLabel().orElse(null); if (roleLabel == null || !Schema.MetaSchema.isMetaLabel(roleLabel)) { inferredRelationPlayers.add(RelationPlayer.of(rolePattern, varName.admin())); allocatedRelationPlayers.add(rp);
if(Schema.MetaSchema.isMetaLabel(superRelationType.label()) || superRelationType.isAbstract()){ //If super type is a meta type no validation needed return Collections.emptySet();
/** * NB: assumes MATCH semantics - all types and their subs are considered * @param parentRole parent {@link Role} * @param parentType parent {@link Type} * @param entryRoles entry set of possible {@link Role}s * @return set of playable {@link Role}s defined by type-role parent combination, parent role assumed as possible */ public static Set<Role> compatibleRoles(Role parentRole, Type parentType, Set<Role> entryRoles) { Set<Role> compatibleRoles = parentRole != null? Sets.newHashSet(parentRole) : Sets.newHashSet(); if (parentRole != null && !Schema.MetaSchema.isMetaLabel(parentRole.label()) ){ compatibleRoles.addAll( Sets.intersection( new RoleConverter().toCompatibleRoles(parentRole).collect(toSet()), entryRoles )); } else { compatibleRoles.addAll(entryRoles); } if (parentType != null && !Schema.MetaSchema.isMetaLabel(parentType.label())) { Set<Role> compatibleRolesFromTypes = new TypeConverter().toCompatibleRoles(parentType).collect(toSet()); //do set intersection meta role compatibleRoles = compatibleRoles.stream() .filter(role -> Schema.MetaSchema.isMetaLabel(role.label()) || compatibleRolesFromTypes.contains(role)) .collect(toSet()); //parent role also possible if (parentRole != null) compatibleRoles.add(parentRole); } return compatibleRoles; }
/** * 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; }
@Override public Set<String> validateOntologically() { Set<String> errors = new HashSet<>(); SchemaConcept type = getSchemaConcept(); if (type != null && !type.isRelationshipType()){ errors.add(ErrorMessage.VALIDATION_RULE_INVALID_RELATION_TYPE.getMessage(type.label())); return errors; } //check role-type compatibility Map<Var, Type> varTypeMap = getParentQuery().getVarTypeMap(); for (Map.Entry<Role, Collection<Var>> e : getRoleVarMap().asMap().entrySet() ){ Role role = e.getKey(); if (!Schema.MetaSchema.isMetaLabel(role.label())) { //check whether this role can be played in this relation if (type != null && type.asRelationshipType().roles().noneMatch(r -> r.equals(role))) { errors.add(ErrorMessage.VALIDATION_RULE_ROLE_CANNOT_BE_PLAYED.getMessage(role.label(), type.label())); } //check whether the role player's type allows playing this role for (Var player : e.getValue()) { Type playerType = varTypeMap.get(player); if (playerType != null && playerType.playing().noneMatch(plays -> plays.equals(role))) { errors.add(ErrorMessage.VALIDATION_RULE_TYPE_CANNOT_PLAY_ROLE.getMessage(playerType.label(), role.label(), type == null? "" : type.label())); } } } } return errors; }
/** * Utility method used to create an instance of this type * * @param instanceBaseType The base type of the instances of this type * @param producer The factory method to produce the instance * @param checkNeeded indicates if a check is necessary before adding the instance * @return A new instance */ V addInstance(Schema.BaseType instanceBaseType, BiFunction<VertexElement, T, V> producer, boolean isInferred, boolean checkNeeded){ if(checkNeeded) preCheckForInstanceCreation(); if(isAbstract()) throw GraknTxOperationException.addingInstancesToAbstractType(this); VertexElement instanceVertex = vertex().tx().addVertexElement(instanceBaseType); if(!Schema.MetaSchema.isMetaLabel(label())) { vertex().tx().txCache().addedInstance(id()); if(isInferred) instanceVertex.property(Schema.VertexProperty.IS_INFERRED, true); } V instance = producer.apply(instanceVertex, getThis()); assert instance != null : "producer should never return null"; return instance; }
private Set<String> validateRelationPlayers(Rule rule){ Set<String> errors = new HashSet<>(); getRelationPlayers().forEach(rp -> { VarPatternAdmin role = rp.getRole().orElse(null); if (role == null){ errors.add(ErrorMessage.VALIDATION_RULE_ILLEGAL_HEAD_RELATION_WITH_AMBIGUOUS_ROLE.getMessage(rule.then(), rule.label())); } else { Label roleLabel = role.getTypeLabel().orElse(null); if (roleLabel == null){ errors.add(ErrorMessage.VALIDATION_RULE_ILLEGAL_HEAD_RELATION_WITH_AMBIGUOUS_ROLE.getMessage(rule.then(), rule.label())); } else { if (Schema.MetaSchema.isMetaLabel(roleLabel)) { errors.add(ErrorMessage.VALIDATION_RULE_ILLEGAL_HEAD_RELATION_WITH_AMBIGUOUS_ROLE.getMessage(rule.then(), rule.label())); } Role roleType = tx().getRole(roleLabel.getValue()); if (roleType != null && roleType.isImplicit()) { errors.add(ErrorMessage.VALIDATION_RULE_ILLEGAL_HEAD_RELATION_WITH_IMPLICIT_ROLE.getMessage(rule.then(), rule.label())); } } } }); return errors; }
/** * * @param isAbstract Specifies if the concept is abstract (true) or not (false). * If the concept type is abstract it is not allowed to have any instances. * @return The Type itself. */ public T isAbstract(Boolean isAbstract) { if(!Schema.MetaSchema.isMetaLabel(label()) && isAbstract && instancesDirect().findAny().isPresent()){ throw GraknTxOperationException.addingInstancesToAbstractType(this); } property(Schema.VertexProperty.IS_ABSTRACT, isAbstract); cachedIsAbstract.set(isAbstract); if(isAbstract){ vertex().tx().txCache().removeFromValidation(this); } else { vertex().tx().txCache().trackForValidation(this); } return getThis(); }
/** * @param parent type * @param child type * @return true if child is a subtype of parent */ public static boolean typesCompatible(SchemaConcept parent, SchemaConcept child) { if (parent == null) return true; if (child == null) return false; if (Schema.MetaSchema.isMetaLabel(parent.label())) return true; SchemaConcept superType = child; while(superType != null && !Schema.MetaSchema.isMetaLabel(superType.label())){ if (superType.equals(parent)) return true; superType = superType.sup(); } return false; }
@SuppressWarnings("unchecked") @Override public <V> AttributeType<V> putAttributeType(Label label, AttributeType.DataType<V> dataType) { @SuppressWarnings("unchecked") AttributeType<V> attributeType = putSchemaConcept(label, Schema.BaseType.ATTRIBUTE_TYPE, false, v -> factory().buildAttributeType(v, getMetaAttributeType(), dataType)); //These checks is needed here because caching will return a type by label without checking the datatype if (Schema.MetaSchema.isMetaLabel(label)) { throw GraknTxOperationException.metaTypeImmutable(label); } else if (!dataType.equals(attributeType.dataType())) { throw GraknTxOperationException.immutableProperty(attributeType.dataType(), dataType, Schema.VertexProperty.DATA_TYPE); } return attributeType; }
public EntityType entityType(OWLClass owlclass) { EntityType type = tx.putEntityType(namer.classEntityTypeLabel(owlclass.getIRI())); EntityType thing = owlThingEntityType(); if (Schema.MetaSchema.isMetaLabel(type.sup().getLabel()) && !type.equals(thing)) { type.sup(thing); } return type; }
/** * Checks if we are mutating a {@link SchemaConcept} in a valid way. {@link SchemaConcept} mutations are valid if: * 1. The {@link SchemaConcept} is not a meta-type * 2. The graph is not batch loading */ void checkSchemaMutationAllowed(){ vertex().tx().checkSchemaMutationAllowed(); if(Schema.MetaSchema.isMetaLabel(label())){ throw GraknTxOperationException.metaTypeImmutable(label()); } }
/** * Throws an exception when adding a {@link SchemaConcept} using a {@link Label} which is already taken */ private GraknTxOperationException labelTaken(SchemaConcept schemaConcept) { if (Schema.MetaSchema.isMetaLabel(schemaConcept.label())) { return GraknTxOperationException.reservedLabel(schemaConcept.label()); } return PropertyNotUniqueException.cannotCreateProperty(schemaConcept, Schema.VertexProperty.SCHEMA_LABEL, schemaConcept.label()); }
public void addRolePlayer(Role role, Thing thing) { Objects.requireNonNull(role); Objects.requireNonNull(thing); if(Schema.MetaSchema.isMetaLabel(role.label())) throw GraknTxOperationException.metaTypeImmutable(role.label()); //Do the actual put of the role and role player putRolePlayerEdge(role, thing); }
/** * Get all the {@link SchemaConcept}s in a graph. * @return a stream of all {@link SchemaConcept}s with non-reserved IDs */ private Stream<? extends SchemaConcept> schemaConcepts(){ Stream<? extends Type> types = tx.admin().getMetaConcept().subs(); Stream<Role> roles = tx.admin().getMetaRole().subs(); Stream<Rule> rules = tx.admin().getMetaRule().subs(); return Stream.of(types, roles, rules) .flatMap(Function.identity()) .filter(t -> !Schema.MetaSchema.isMetaLabel(t.label())); } }
/** * @param schemaConcept input type * @return set of all non-meta super types of the role */ public static Set<SchemaConcept> supers(SchemaConcept schemaConcept){ Set<SchemaConcept> superTypes = new HashSet<>(); SchemaConcept superType = schemaConcept.sup(); while(superType != null && !Schema.MetaSchema.isMetaLabel(superType.label())) { superTypes.add(superType); superType = superType.sup(); } return superTypes; }
/** * Checks if an {@link Thing} is allowed to be created and linked to this {@link Type}. * This can fail is the {@link ai.grakn.GraknTxType} is read only. * It can also fail when attempting to attach an {@link ai.grakn.concept.Attribute} to a meta type */ private void preCheckForInstanceCreation(){ vertex().tx().checkMutationAllowed(); if(Schema.MetaSchema.isMetaLabel(label())){ throw GraknTxOperationException.metaTypeImmutable(label()); } }