/** * * @param role The Role to validate * @return An error message if the relates does not have a single incoming RELATES edge */ static Optional<String> validateHasSingleIncomingRelatesEdge(Role role){ if(!role.relationships().findAny().isPresent()) { return Optional.of(VALIDATION_ROLE_TYPE_MISSING_RELATION_TYPE.getMessage(role.label())); } return Optional.empty(); }
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); }
@Override public String innerToString(){ StringBuilder description = new StringBuilder(); description.append("ID [").append(id()).append("] Type [").append(type().label()).append("] Roles and Role Players: \n"); for (Map.Entry<Role, Set<Thing>> entry : allRolePlayers().entrySet()) { if(entry.getValue().isEmpty()){ description.append(" Role [").append(entry.getKey().label()).append("] not played by any instance \n"); } else { StringBuilder instancesString = new StringBuilder(); for (Thing thing : entry.getValue()) { instancesString.append(thing.id()).append(","); } description.append(" Role [").append(entry.getKey().label()).append("] played by ["). append(instancesString.toString()).append("] \n"); } } return description.toString(); }
/** * Add relates edges to a var, given a type * @param var var to be modified * @param type type from which metadata extracted * @return var with appropriate relates edges */ private static VarPattern relates(VarPattern var, RelationshipType type){ for(Role role:type.roles().collect(Collectors.toSet())){ var = var.relates(Graql.label(role.label())); } return var; }
/** * 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; }
private Multimap<Role, RelationPlayer> getRoleRelationPlayerMap(){ Multimap<Role, RelationPlayer> roleRelationPlayerMap = ArrayListMultimap.create(); Multimap<Role, Var> roleVarMap = getRoleVarMap(); List<RelationPlayer> relationPlayers = getRelationPlayers(); roleVarMap.asMap().forEach((role, value) -> { Label roleLabel = role.label(); relationPlayers.stream() .filter(rp -> rp.getRole().isPresent()) .forEach(rp -> { VarPatternAdmin roleTypeVar = rp.getRole().orElse(null); Label rl = roleTypeVar != null ? roleTypeVar.getTypeLabel().orElse(null) : null; if (roleLabel != null && roleLabel.equals(rl)) { roleRelationPlayerMap.put(role, rp); } }); }); return roleRelationPlayerMap; }
private Stream<AttributeType> attributes(Schema.ImplicitType implicitType){ //TODO: Make this less convoluted String [] implicitIdentifiers = implicitType.getLabel("").getValue().split("--"); String prefix = implicitIdentifiers[0] + "-"; String suffix = "-" + implicitIdentifiers[1]; //A traversal is not used in this so that caching can be taken advantage of. return playing().map(role -> role.label().getValue()). filter(roleLabel -> roleLabel.startsWith(prefix) && roleLabel.endsWith(suffix)). map(roleLabel -> { String attributeTypeLabel = roleLabel.replace(prefix, "").replace(suffix, ""); return vertex().tx().getAttributeType(attributeTypeLabel); }); }
/** * @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))); }
/** * 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; }
/** * Add the roleplayers of a {@link Relationship} to the relationship var * @param var var representing the relationship * @param relationship {@link Relationship} that contains roleplayer data * @return var pattern with roleplayers */ private static VarPattern roleplayers(VarPattern var, Relationship relationship){ for(Map.Entry<Role, Set<Thing>> entry: relationship.rolePlayersMap().entrySet()){ Role role = entry.getKey(); for (Thing thing : entry.getValue()) { var = var.rel(Graql.label(role.label()), thing.id().getValue()); } } return var; }
@Override Label transform(MatchableConcept item) { Concept concept = item.get(); return concept.isRole() ? concept.asRole().label() : null; } };
/** * Checks if the {@link Role} of the {@link Casting} has been linked to the {@link RelationshipType} of * the {@link Relationship} which the {@link Casting} connects to. * * @param role the {@link Role} which the {@link Casting} refers to * @param relationshipType the {@link RelationshipType} which should connect to the role * @param relationship the {@link Relationship} which the {@link Casting} refers to * @return an error if one is found */ private static Optional<String> roleNotLinkedToRelationShip(Role role, RelationshipType relationshipType, Relationship relationship){ boolean notFound = role.relationships(). noneMatch(innerRelationType -> innerRelationType.label().equals(relationshipType.label())); if(notFound){ return Optional.of(VALIDATION_RELATION_CASTING_LOOP_FAIL.getMessage(relationship.id(), role.label(), relationshipType.label())); } return Optional.empty(); }
/** * 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())); }
@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; }
/** * @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; }
Role rolePlayed = playsEntry.getKey(); Boolean required = playsEntry.getValue(); if(rolePlayed.label().equals(role.label())){ satisfiesPlays = true; return Optional.of(VALIDATION_REQUIRED_RELATION.getMessage(thing.id(), thing.type().label(), role.label(), thing.relationships(role).count())); return Optional.empty(); } else { return Optional.of(VALIDATION_CASTING.getMessage(thing.type().label(), thing.id(), role.label()));
/** * * @param thing The thing to be validated * @return An error message if the thing does not have all the required resources */ static Optional<String> validateInstancePlaysAllRequiredRoles(Thing thing) { TypeImpl<?, ?> currentConcept = (TypeImpl) thing.type(); while(currentConcept != null){ Map<Role, Boolean> plays = currentConcept.directPlays(); for (Map.Entry<Role, Boolean> playsEntry : plays.entrySet()) { if(playsEntry.getValue()){ Role role = playsEntry.getKey(); // Assert there is a relationship for this type Stream<Relationship> relationships = thing.relationships(role); if(!CommonUtil.containsOnly(relationships, 1)){ Label resourceTypeLabel = Schema.ImplicitType.explicitLabel(role.label()); return Optional.of(VALIDATION_NOT_EXACTLY_ONE_KEY.getMessage(thing.id(), resourceTypeLabel)); } } } currentConcept = (TypeImpl) currentConcept.sup(); } return Optional.empty(); }
public Pattern pattern(Relationship concept) { VarPattern relationPattern = Graql.var(); Set<Pattern> idPatterns = new HashSet<>(); for (Map.Entry<Role, Set<Thing>> entry : concept.rolePlayersMap().entrySet()) { for (Thing var : entry.getValue()) { Var rolePlayer = Graql.var(); relationPattern = relationPattern.rel(Graql.label(entry.getKey().label()), rolePlayer); idPatterns.add(rolePlayer.asUserDefined().id(var.id())); } } relationPattern = relationPattern.isa(Graql.label(concept.type().label())); Pattern pattern = relationPattern; for (Pattern idPattern : idPatterns) { pattern = pattern.and(idPattern); } return pattern; } }
@Override public String toString() { if (concept.isAttribute()) { return "hasValue(" + valueToString(concept.asAttribute().value()) + ")"; } else if (concept.isThing()) { Thing thing = concept.asThing(); Stream<Attribute<?>> resources = thing.attributes(); Optional<?> value = resources .filter(resource -> NAME_TYPES.contains(resource.type().label())) .map(Attribute::value).findFirst(); return "instance(" + value.map(StringUtil::valueToString).orElse("") + ") isa " + thing.type().label(); } else if (concept.isType()) { return "type(" + concept.asType().label() + ")"; } else if (concept.isRole()) { return "role(" + concept.asRole().label() + ")"; } else if (concept.isRule()) { return "rule(" + concept.asRule().label() + ")"; } else { throw CommonUtil.unreachableStatement("Unrecognised concept " + concept); } }