Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(candeletecardinalities): return canDoResponse of false instead of throwing an exception for inherited cardinalities (DEV-314) #1966

Merged
Expand Up @@ -52,7 +52,6 @@ object Cardinalities {
)(implicit ec: ExecutionContext, stringFormatter: StringFormatter, timeout: Timeout): Future[CanDoResponseV2] = {
for {
cacheData: Cache.OntologyCacheData <- Cache.getCacheData
ontology = cacheData.ontologies(internalOntologyIri)

submittedClassDefinition: ClassInfoContentV2 =
deleteCardinalitiesFromClassRequest.classInfoContent.toOntologySchema(InternalSchema)
Expand Down Expand Up @@ -106,9 +105,20 @@ object Cardinalities {
cardinalitiesToDelete: Map[SmartIri, Cardinality.KnoraCardinalityInfo] =
deleteCardinalitiesFromClassRequest.classInfoContent.toOntologySchema(InternalSchema).directCardinalities

_ = cardinalitiesToDelete.foreach(p =>
isCardinalityDefinedOnClass(cacheData, p._1, p._2, internalClassIri, internalOntologyIri)
)
isDefinedOnClassList: List[Boolean] <- Future
.sequence(cardinalitiesToDelete.map { p =>
for {
isDefined: Boolean <- isCardinalityDefinedOnClass(
cacheData,
p._1,
p._2,
internalClassIri,
internalOntologyIri
)
} yield isDefined
}.toList)

atLeastOneCardinalityNotDefinedOnClass: Boolean = isDefinedOnClassList.contains(false)

// Check if property is used in resources of this class

Expand Down Expand Up @@ -176,7 +186,9 @@ object Cardinalities {
throw BadRequestException(msg)
}
)
} yield CanDoResponseV2(!propertyIsUsed)

// response is true only when property is not used in data and cardinality is defined directly on that class
} yield CanDoResponseV2(!propertyIsUsed && !atLeastOneCardinalityNotDefinedOnClass)
}

/**
Expand Down Expand Up @@ -250,9 +262,24 @@ object Cardinalities {
cardinalitiesToDelete: Map[SmartIri, Cardinality.KnoraCardinalityInfo] =
deleteCardinalitiesFromClassRequest.classInfoContent.toOntologySchema(InternalSchema).directCardinalities

_ = cardinalitiesToDelete.foreach(p =>
isCardinalityDefinedOnClass(cacheData, p._1, p._2, internalClassIri, internalOntologyIri)
)
isDefinedOnClassList: List[Boolean] <- Future
.sequence(cardinalitiesToDelete.map { p =>
for {
isDefined: Boolean <- isCardinalityDefinedOnClass(
cacheData,
p._1,
p._2,
internalClassIri,
internalOntologyIri
)
} yield isDefined
}.toList)

_ = if (isDefinedOnClassList.contains(false)) {
throw BadRequestException(
"The cardinality is not defined directly on the class and cannot be deleted."
)
}
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved

// Check if property is used in resources of this class

Expand Down Expand Up @@ -484,25 +511,6 @@ object Cardinalities {
.entityInfoContent
} yield currentClassDefinition

/**
* Checks if the class is a subclass of `knora-base:Resource`.
*
* @param submittedClassInfoContentV2 the class to check
* @return `true` if the class is a subclass of `knora-base:Resource`, otherwise throws an exception.
*/
def isKnoraResourceClass(
submittedClassInfoContentV2: ClassInfoContentV2
)(implicit ec: ExecutionContext, stringFormatter: StringFormatter): Future[Boolean] =
if (submittedClassInfoContentV2.subClassOf.contains(KnoraBase.Resource.toSmartIri)) {
FastFuture.successful(true)
} else {
FastFuture.failed(
throw BadRequestException(
s"Class ${submittedClassInfoContentV2.classIri} is not a subclass of ${KnoraBase.Resource.toSmartIri}. $submittedClassInfoContentV2"
)
)
}

/**
* Check if the cardinality for a property is defined on a class.
*
Expand All @@ -511,7 +519,7 @@ object Cardinalities {
* @param cardinalityInfo the cardinality that should be defined for the property.
* @param internalClassIri the class we are checking against.
* @param internalOntologyIri the ontology containing the class.
* @return `true` if the cardinality is defined on the class, otherwise throws an exception.
* @return `true` if the cardinality is defined on the class, `false` otherwise
*/
def isCardinalityDefinedOnClass(
cacheData: Cache.OntologyCacheData,
Expand All @@ -521,30 +529,58 @@ object Cardinalities {
internalOntologyIri: SmartIri
)(implicit ec: ExecutionContext): Future[Boolean] = {
val currentOntologyState: ReadOntologyV2 = cacheData.ontologies(internalOntologyIri)
val currentClassState: ClassInfoContentV2 = currentOntologyState.classes

val readClassInfo: ReadClassInfoV2 = currentOntologyState.classes
.getOrElse(
internalClassIri,
throw BadRequestException(
s"Class ${internalClassIri} does not exist"
s"Class $internalClassIri does not exist"
)
)
.entityInfoContent
val existingCardinality = currentClassState.directCardinalities
.getOrElse(
propertyIri,

// if cardinality is inherited, it's not directly defined on that class
if (readClassInfo.inheritedCardinalities.keySet.contains(propertyIri)) {
return FastFuture.successful(false)
}

val currentClassState: ClassInfoContentV2 = readClassInfo.entityInfoContent
val existingCardinality = currentClassState.directCardinalities.get(propertyIri)
existingCardinality match {
case Some(cardinality) =>
if (cardinality.cardinality.equals(cardinalityInfo.cardinality)) {
FastFuture.successful(true)
} else {
FastFuture.failed(
throw BadRequestException(
s"Submitted cardinality for property $propertyIri does not match existing cardinality."
)
)
}
case None =>
throw BadRequestException(
s"Cardinality for property ${propertyIri} is not defined."
s"Submitted cardinality for property $propertyIri is not defined for class $internalClassIri."
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
)
)
if (existingCardinality.cardinality.equals(cardinalityInfo.cardinality)) {
}

}

/**
* Checks if the class is a subclass of `knora-base:Resource`.
*
* @param submittedClassInfoContentV2 the class to check
* @return `true` if the class is a subclass of `knora-base:Resource`, otherwise throws an exception.
*/
def isKnoraResourceClass(
submittedClassInfoContentV2: ClassInfoContentV2
)(implicit ec: ExecutionContext, stringFormatter: StringFormatter): Future[Boolean] =
if (submittedClassInfoContentV2.subClassOf.contains(KnoraBase.Resource.toSmartIri)) {
FastFuture.successful(true)
} else {
FastFuture.failed(
throw BadRequestException(
s"Submitted cardinality for property ${propertyIri} does not match existing cardinality."
s"Class ${submittedClassInfoContentV2.classIri} is not a subclass of ${KnoraBase.Resource.toSmartIri}. $submittedClassInfoContentV2"
)
)
}
}

}