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(cardinality): Check cardinality with multiple inherited classes (DEV-1189) #2164

Merged
merged 25 commits into from Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion Makefile
Expand Up @@ -209,7 +209,6 @@ test: build ## runs all tests
sbt -v coverage "userHandler/test"
sbt -v coverage "userInterface/test"
sbt -v coverage "userRepo/test"
sbt -v coverage "valueObjects/test"
sbt -v coverage "webapi/test"
sbt coverageAggregate

Expand Down
12 changes: 1 addition & 11 deletions build.sbt
Expand Up @@ -27,7 +27,7 @@ lazy val buildSettings = Seq(
lazy val rootBaseDir = ThisBuild / baseDirectory

lazy val root: Project = Project(id = "root", file("."))
.aggregate(webapi, sipi, shared, valueObjects, userCore, userHandler, userRepo, userInterface)
.aggregate(webapi, sipi, shared, userCore, userHandler, userRepo, userInterface)
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
.enablePlugins(GitVersioning, GitBranchPrompt)
.settings(
// values set for all sub-projects
Expand Down Expand Up @@ -231,16 +231,6 @@ lazy val webapiJavaTestOptions = Seq(
// DSP's new codebase
//////////////////////////////////////

// Value Objects project

lazy val valueObjects = project
.in(file("dsp-value-objects"))
.settings(
name := "valueObjects",
libraryDependencies ++= Dependencies.valueObjectsLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)

// Role projects

lazy val roleInterface = project
Expand Down
2 changes: 1 addition & 1 deletion docs/02-knora-ontologies/knora-base.md
Expand Up @@ -32,7 +32,7 @@ In Knora, each item of data belongs to some particular project. Each project usi

- `projectShortname` (1): A short name that can be used to identify the project in configuration files and the like.

- `projectLongname` (1): The full name of the project.
- `projectLongname` (0-1): The full name of the project.
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved

- `projectShortcode` (1): A hexadecimal code that uniquely identifies the project. These codes are assigned to projects
by the [DaSCH](http://dasch.swiss/).
Expand Down
2 changes: 1 addition & 1 deletion docs/Readme.md
Expand Up @@ -3,7 +3,7 @@
## MkDocs Documentation

This folder contains the sources to the DSP-API documentation website published
under <http://docs-api.dasch.swiss>
under <https://docs.dasch.swiss/>

The `src` folder contains the following documentation sources:

Expand Down
@@ -0,0 +1,47 @@
/*
* Copyright © 2021 - 2022 Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
* SPDX-License-Identifier: Apache-2.0
*/

package dsp.schema.domain

/**
* Represents a cardinality value object.
*/
sealed trait Cardinality { self =>

/**
* The string representation of the cardinality
*/
val value: String

/**
* Checks whether a cardinality is stricter than another one.
*
* @param that the cardinality to be compared against
* @return `true` if the present cardinality is stricter than `that`, `false` otherwise
*/
def isStricterThan(that: Cardinality): Boolean =
if (self == that) {
false
} else {
self match {
case MustHaveOne => true
case MustHaveSome => that == MayHaveMany
case MayHaveOne => that == MayHaveMany
case MayHaveMany => false
}
}
}
object MustHaveOne extends Cardinality {
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
override val value: String = "1"
}
object MustHaveSome extends Cardinality {
override val value: String = "1-n"
}
object MayHaveOne extends Cardinality {
override val value: String = "0-1"
}
object MayHaveMany extends Cardinality {
override val value: String = "0-n"
}
Expand Up @@ -32,7 +32,7 @@ object SchemaCommandsSpec extends ZIOSpecDefault {
comment = Some(commentLangString)
guiAttribute <- Schema.GuiAttribute.make("hlist=<http://rdfh.ch/lists/082F/PbRLUy66TsK10qNP1mBwzA>")
guiElement <- Schema.GuiElement.make(SalsahGui.List)
guiObject <- Schema.GuiObject.make(guiAttributes = List(guiAttribute), guiElement = Some(guiElement))
guiObject <- Schema.GuiObject.make(guiAttributes = Set(guiAttribute), guiElement = Some(guiElement))
command = CreatePropertyCommand.make(
ontologyIri = ontologyIri,
lastModificationDate = lastModificationDate,
Expand Down
51 changes: 51 additions & 0 deletions test_data/ontologies/freetest-onto.ttl
Expand Up @@ -99,6 +99,57 @@
salsah-gui:guiElement salsah-gui:List ;
salsah-gui:guiAttribute "hlist=<http://rdfh.ch/lists/0001/free-test-list>" .

:hasPublicationDate
rdf:type owl:ObjectProperty ;
rdfs:subPropertyOf knora-base:hasValue ;
rdfs:label "Publikationsdatum"@de,
"Publication date"@en ;
knora-base:objectClassConstraint knora-base:TextValue ;
salsah-gui:guiElement salsah-gui:SimpleText ;
salsah-gui:guiAttribute "size=80",
"maxlength=255" .

:PubMayHaveMany
rdf:type owl:Class ;
rdfs:subClassOf knora-base:Resource,
[ rdf:type owl:Restriction ;
owl:onProperty :hasPublicationDate ;
owl:minCardinality "0"^^xsd:nonNegativeInteger ;
salsah-gui:guiOrder "1"^^xsd:nonNegativeInteger ];
rdfs:label "0-n"@en;
rdfs:comment """A comment"""@de .

:PubMayHaveOne
rdf:type owl:Class ;
rdfs:subClassOf knora-base:Resource,
[ rdf:type owl:Restriction ;
owl:onProperty :hasPublicationDate ;
owl:maxCardinality "1"^^xsd:nonNegativeInteger ;
salsah-gui:guiOrder "1"^^xsd:nonNegativeInteger ];
rdfs:label "0-1"@en;
rdfs:comment """A comment"""@de .

:PubMustHaveSome
rdf:type owl:Class ;
rdfs:subClassOf knora-base:Resource,
[ rdf:type owl:Restriction ;
owl:onProperty :hasPublicationDate ;
owl:minCardinality "1"^^xsd:nonNegativeInteger ;
salsah-gui:guiOrder "1"^^xsd:nonNegativeInteger ];
rdfs:label "1-n"@en;
rdfs:comment """A comment"""@de .

:PubMustHaveOne
rdf:type owl:Class ;
rdfs:subClassOf knora-base:Resource,
[ rdf:type owl:Restriction ;
owl:onProperty :hasPublicationDate ;
owl:cardinality "1"^^xsd:nonNegativeInteger ;
salsah-gui:guiOrder "1"^^xsd:nonNegativeInteger ];
rdfs:label "1"@en;
rdfs:comment """A comment"""@de .




:FreeTest
Expand Down
Expand Up @@ -5,10 +5,11 @@

package org.knora.webapi.messages.util

import dsp.schema.domain._
import org.apache.commons.text.StringEscapeUtils
import org.knora.webapi.OntologySchema
import org.knora.webapi.messages.SmartIri
import org.knora.webapi.messages.v2.responder.ontologymessages.Cardinality
import org.knora.webapi.messages.v2.responder.ontologymessages.OwlCardinality

import java.time.Instant
import scala.reflect.runtime.{universe => ru}
Expand Down Expand Up @@ -58,23 +59,22 @@ object MessageUtil {
case instant: Instant => "Instant.parse(\"" + instant.toString + "\")"
case None => "None"

// Handle enumerations.

case cardinality: Cardinality.Value =>
// Handle value objects.
case cardinality: Cardinality =>
cardinality match {
case Cardinality.MayHaveOne => "Cardinality.MayHaveOne"
case Cardinality.MayHaveMany => "Cardinality.MayHaveMany"
case Cardinality.MustHaveOne => "Cardinality.MustHaveOne"
case Cardinality.MustHaveSome => "Cardinality.MustHaveSome"
case MayHaveOne => "MayHaveOne"
case MayHaveMany => "MayHaveMany"
case MustHaveOne => "MustHaveOne"
case MustHaveSome => "MustHaveSome"
}

// Handle enumerations.
case enumVal if enumVal.getClass.getName == "scala.Enumeration$Val" => enumVal.toString

case ontologySchema: OntologySchema =>
ontologySchema.getClass.getSimpleName.stripSuffix("$")

// Handle collections.

case Nil => "Nil"

case list: Seq[Any @unchecked] =>
Expand Down
Expand Up @@ -6,11 +6,12 @@
package org.knora.webapi.messages.util.standoff

import akka.actor.ActorRef
import com.typesafe.scalalogging.Logger
import akka.pattern.ask
import akka.util.Timeout
import org.knora.webapi.IRI
import com.typesafe.scalalogging.Logger
import dsp.errors._
import dsp.schema.domain._
import org.knora.webapi.IRI
import org.knora.webapi.messages.IriConversions._
import org.knora.webapi.messages.OntologyConstants
import org.knora.webapi.messages.SmartIri
Expand All @@ -23,7 +24,7 @@ import org.knora.webapi.messages.v1.responder.valuemessages.JulianDayNumberValue
import org.knora.webapi.messages.v1.responder.valuemessages.KnoraCalendarV1
import org.knora.webapi.messages.v1.responder.valuemessages.KnoraPrecisionV1
import org.knora.webapi.messages.v1.responder.valuemessages.UpdateValueV1
import org.knora.webapi.messages.v2.responder.ontologymessages.Cardinality.KnoraCardinalityInfo
import org.knora.webapi.messages.v2.responder.ontologymessages.OwlCardinality._
import org.knora.webapi.messages.v2.responder.ontologymessages._
import org.knora.webapi.messages.v2.responder.standoffmessages._
import org.knora.webapi.settings.KnoraSettingsImpl
Expand Down Expand Up @@ -208,7 +209,7 @@ object StandoffTagUtilV2 {

// filter all the required props
val mustExistOnce: Set[SmartIri] = classSpecificProps.filter { case (propIri, card) =>
card.cardinality == Cardinality.MustHaveOne || card.cardinality == Cardinality.MustHaveSome
card.cardinality == MustHaveOne || card.cardinality == MustHaveSome
}.keySet

// check if all the min cardinalities are respected
Expand All @@ -225,7 +226,7 @@ object StandoffTagUtilV2 {

// filter all the props that have a limited occurrence
val mayExistOnce = classSpecificProps.filter { case (propIri, card) =>
card.cardinality == Cardinality.MustHaveOne || card.cardinality == Cardinality.MayHaveOne
card.cardinality == MustHaveOne || card.cardinality == MayHaveOne
}.keySet

// check if all the max cardinalities are respected
Expand Down
Expand Up @@ -6,16 +6,17 @@
package org.knora.webapi.messages.v1.responder.ontologymessages

import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import dsp.schema.domain.Cardinality
import org.knora.webapi._
import org.knora.webapi.messages.IriConversions._
import org.knora.webapi.messages.ResponderRequest.KnoraRequestV1
import org.knora.webapi.messages.SmartIri
import org.knora.webapi.messages.StringFormatter
import org.knora.webapi.messages.admin.responder.usersmessages.UserADM
import org.knora.webapi.messages.store.triplestoremessages.StringLiteralV2
import org.knora.webapi.messages.ResponderRequest.KnoraRequestV1
import org.knora.webapi.messages.v1.responder.KnoraResponseV1
import org.knora.webapi.messages.v2.responder.ontologymessages.Cardinality.KnoraCardinalityInfo
import org.knora.webapi.messages.v2.responder.ontologymessages.EntityInfoContentV2
import org.knora.webapi.messages.v2.responder.ontologymessages.OwlCardinality.KnoraCardinalityInfo
import org.knora.webapi.messages.v2.responder.ontologymessages.ReadClassInfoV2
import org.knora.webapi.messages.v2.responder.ontologymessages._
import org.knora.webapi.messages.v2.responder.standoffmessages.StandoffDataTypeClasses
Expand Down Expand Up @@ -614,7 +615,6 @@ case class PropertyTypeV1(id: IRI, label: String) {
* A spray-json protocol for generating Knora API v1 JSON providing data about resources and their properties.
*/
object ResourceTypeV1JsonProtocol extends SprayJsonSupport with DefaultJsonProtocol with NullOptions {

implicit val propertyDefinitionV1Format: JsonFormat[PropertyDefinitionV1] = jsonFormat10(PropertyDefinitionV1)
implicit val propertyDefinitionInNamedGraphV1Format: JsonFormat[PropertyDefinitionInNamedGraphV1] = jsonFormat8(
PropertyDefinitionInNamedGraphV1
Expand Down