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
refactor: move value objects to separate project (DEV-615) #2069
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
0ca212a
add new project and deps
mpro7 aea668a
move value objects to separate ptoject
mpro7 c844fa0
move & refactor error messages
mpro7 e23f1e5
copy temporarily + adjust v2 validation related stuff
mpro7 d3f4761
fix all errors but StringLiteralV2
mpro7 a5c1265
fix StringLiteralV2 class related issues
mpro7 afc3830
fix admin tests
mpro7 4586b24
move tests to new project
mpro7 47da536
rewrite tests to ZIO
mpro7 00f4cbc
Merge branch 'main' into DEV-615-add-value-objects-sbt-project
mpro7 2cebe77
fixt tests
mpro7 6ec5708
refactor IRI type property names
mpro7 430caed
cleanup
mpro7 20b65cf
review changes
mpro7 6bd4eb4
more review changes
mpro7 43f4f46
even more review changes
mpro7 File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
dsp-value-objects/src/main/scala/dsp/valueobjects/Group.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* Copyright © 2021 - 2022 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package dsp.valueobjects | ||
|
||
import zio.prelude.Validation | ||
|
||
object Group { | ||
|
||
/** | ||
* GroupName value object. | ||
*/ | ||
sealed abstract case class GroupName private (value: String) | ||
object GroupName { self => | ||
def make(value: String): Validation[Throwable, GroupName] = | ||
if (value.isEmpty) { | ||
Validation.fail(V2.BadRequestException(GroupErrorMessages.GroupNameMissing)) | ||
} else { | ||
val validatedValue = Validation( | ||
V2IriValidation.toSparqlEncodedString( | ||
value, | ||
throw V2.BadRequestException(GroupErrorMessages.GroupNameInvalid) | ||
) | ||
) | ||
|
||
validatedValue.map(new GroupName(_) {}) | ||
} | ||
|
||
def make(value: Option[String]): Validation[Throwable, Option[GroupName]] = | ||
value match { | ||
case Some(v) => self.make(v).map(Some(_)) | ||
case None => Validation.succeed(None) | ||
} | ||
} | ||
|
||
/** | ||
* GroupDescriptions value object. | ||
*/ | ||
sealed abstract case class GroupDescriptions private (value: Seq[V2.StringLiteralV2]) | ||
object GroupDescriptions { self => | ||
def make(value: Seq[V2.StringLiteralV2]): Validation[Throwable, GroupDescriptions] = | ||
if (value.isEmpty) { | ||
Validation.fail(V2.BadRequestException(GroupErrorMessages.GroupDescriptionsMissing)) | ||
} else { | ||
val validatedDescriptions = Validation(value.map { description => | ||
val validatedDescription = | ||
V2IriValidation.toSparqlEncodedString( | ||
description.value, | ||
throw V2.BadRequestException(GroupErrorMessages.GroupDescriptionsInvalid) | ||
) | ||
V2.StringLiteralV2(value = validatedDescription, language = description.language) | ||
}) | ||
validatedDescriptions.map(new GroupDescriptions(_) {}) | ||
} | ||
|
||
def make(value: Option[Seq[V2.StringLiteralV2]]): Validation[Throwable, Option[GroupDescriptions]] = | ||
value match { | ||
case Some(v) => self.make(v).map(Some(_)) | ||
case None => Validation.succeed(None) | ||
} | ||
} | ||
|
||
/** | ||
* GroupStatus value object. | ||
*/ | ||
sealed abstract case class GroupStatus private (value: Boolean) | ||
object GroupStatus { self => | ||
def make(value: Boolean): Validation[Throwable, GroupStatus] = | ||
Validation.succeed(new GroupStatus(value) {}) | ||
def make(value: Option[Boolean]): Validation[Throwable, Option[GroupStatus]] = | ||
value match { | ||
case Some(v) => self.make(v).map(Some(_)) | ||
case None => Validation.succeed(None) | ||
} | ||
} | ||
|
||
/** | ||
* GroupSelfJoin value object. | ||
*/ | ||
sealed abstract case class GroupSelfJoin private (value: Boolean) | ||
object GroupSelfJoin { self => | ||
def make(value: Boolean): Validation[Throwable, GroupSelfJoin] = | ||
Validation.succeed(new GroupSelfJoin(value) {}) | ||
def make(value: Option[Boolean]): Validation[Throwable, Option[GroupSelfJoin]] = | ||
value match { | ||
case Some(v) => self.make(v).map(Some(_)) | ||
case None => Validation.succeed(None) | ||
} | ||
} | ||
} | ||
|
||
object GroupErrorMessages { | ||
val GroupNameMissing = "Group name cannot be empty." | ||
val GroupNameInvalid = "Group name is invalid." | ||
val GroupDescriptionsMissing = "Group description cannot be empty." | ||
val GroupDescriptionsInvalid = "Group description is invalid." | ||
} |
157 changes: 157 additions & 0 deletions
157
dsp-value-objects/src/main/scala/dsp/valueobjects/Iri.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/* | ||
* Copyright © 2021 - 2022 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package dsp.valueobjects | ||
|
||
import zio.prelude.Validation | ||
|
||
sealed trait Iri | ||
object Iri { | ||
|
||
/** | ||
* GroupIri value object. | ||
*/ | ||
sealed abstract case class GroupIri private (value: String) extends Iri | ||
object GroupIri { self => | ||
def make(value: String): Validation[Throwable, GroupIri] = | ||
if (value.isEmpty) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.GroupIriMissing)) | ||
} else { | ||
val isUuid: Boolean = V2UuidValidation.hasUuidLength(value.split("/").last) | ||
|
||
if (!V2IriValidation.isKnoraGroupIriStr(value)) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.GroupIriInvalid)) | ||
} else if (isUuid && !V2UuidValidation.isUuidVersion4Or5(value)) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.UuidVersionInvalid)) | ||
} else { | ||
val validatedValue = Validation( | ||
V2IriValidation.validateAndEscapeIri(value, throw V2.BadRequestException(IriErrorMessages.GroupIriInvalid)) | ||
) | ||
|
||
validatedValue.map(new GroupIri(_) {}) | ||
} | ||
} | ||
|
||
def make(value: Option[String]): Validation[Throwable, Option[GroupIri]] = | ||
value match { | ||
case Some(v) => self.make(v).map(Some(_)) | ||
case None => Validation.succeed(None) | ||
} | ||
} | ||
|
||
/** | ||
* ListIri value object. | ||
*/ | ||
sealed abstract case class ListIri private (value: String) extends Iri | ||
object ListIri { self => | ||
def make(value: String): Validation[Throwable, ListIri] = | ||
if (value.isEmpty) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.ListIriMissing)) | ||
} else { | ||
val isUuid: Boolean = V2UuidValidation.hasUuidLength(value.split("/").last) | ||
|
||
if (!V2IriValidation.isKnoraListIriStr(value)) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.ListIriInvalid)) | ||
} else if (isUuid && !V2UuidValidation.isUuidVersion4Or5(value)) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.UuidVersionInvalid)) | ||
} else { | ||
val validatedValue = Validation( | ||
V2IriValidation.validateAndEscapeIri( | ||
value, | ||
throw V2.BadRequestException(IriErrorMessages.ListIriInvalid) | ||
) | ||
) | ||
|
||
validatedValue.map(new ListIri(_) {}) | ||
} | ||
} | ||
|
||
def make(value: Option[String]): Validation[Throwable, Option[ListIri]] = | ||
value match { | ||
case Some(v) => self.make(v).map(Some(_)) | ||
case None => Validation.succeed(None) | ||
} | ||
} | ||
|
||
/** | ||
* ProjectIri value object. | ||
*/ | ||
sealed abstract case class ProjectIri private (value: String) extends Iri | ||
object ProjectIri { self => | ||
def make(value: String): Validation[Throwable, ProjectIri] = | ||
if (value.isEmpty) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.ProjectIriMissing)) | ||
} else { | ||
val isUuid: Boolean = V2UuidValidation.hasUuidLength(value.split("/").last) | ||
|
||
if (!V2IriValidation.isKnoraProjectIriStr(value)) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.ProjectIriInvalid)) | ||
} else if (isUuid && !V2UuidValidation.isUuidVersion4Or5(value)) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.UuidVersionInvalid)) | ||
} else { | ||
val validatedValue = Validation( | ||
V2IriValidation.validateAndEscapeProjectIri( | ||
value, | ||
throw V2.BadRequestException(IriErrorMessages.ProjectIriInvalid) | ||
) | ||
) | ||
|
||
validatedValue.map(new ProjectIri(_) {}) | ||
} | ||
} | ||
|
||
def make(value: Option[String]): Validation[Throwable, Option[ProjectIri]] = | ||
value match { | ||
case Some(v) => self.make(v).map(Some(_)) | ||
case None => Validation.succeed(None) | ||
} | ||
} | ||
|
||
/** | ||
* UserIri value object. | ||
*/ | ||
sealed abstract case class UserIri private (value: String) extends Iri | ||
object UserIri { self => | ||
def make(value: String): Validation[Throwable, UserIri] = | ||
if (value.isEmpty) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.UserIriMissing)) | ||
} else { | ||
val isUuid: Boolean = V2UuidValidation.hasUuidLength(value.split("/").last) | ||
|
||
if (!V2IriValidation.isKnoraUserIriStr(value)) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.UserIriInvalid)) | ||
} else if (isUuid && !V2UuidValidation.isUuidVersion4Or5(value)) { | ||
Validation.fail(V2.BadRequestException(IriErrorMessages.UuidVersionInvalid)) | ||
} else { | ||
val validatedValue = Validation( | ||
V2IriValidation.validateAndEscapeUserIri( | ||
value, | ||
throw V2.BadRequestException(IriErrorMessages.UserIriInvalid) | ||
) | ||
) | ||
|
||
validatedValue.map(new UserIri(_) {}) | ||
} | ||
} | ||
|
||
def make(value: Option[String]): Validation[Throwable, Option[UserIri]] = | ||
value match { | ||
case Some(v) => self.make(v).map(Some(_)) | ||
case None => Validation.succeed(None) | ||
} | ||
} | ||
} | ||
|
||
object IriErrorMessages { | ||
val GroupIriMissing = "Group IRI cannot be empty." | ||
val GroupIriInvalid = "Group IRI is invalid." | ||
val ListIriMissing = "List IRI cannot be empty." | ||
val ListIriInvalid = "List IRI is invalid" | ||
val ProjectIriMissing = "Project IRI cannot be empty." | ||
val ProjectIriInvalid = "Project IRI is invalid." | ||
val UserIriMissing = "User IRI cannot be empty." | ||
val UserIriInvalid = "User IRI is invalid." | ||
val UuidVersionInvalid = "Invalid UUID used to create IRI. Only versions 4 and 5 are supported." | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure anymore if we discussed the naming of this already. But I think that "description" should be singular. There is only one description per group (and all other entities), just possibly in multiple languages. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is indeed a little bit misleading. Since value objects are going to be refactored in next step, this can be a subject of discussion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree, only one description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine, but technically it is still the Seq of values, which means that the way how the translations/internationalisation is implemented is wrong. Nothing stops user from adding more than one description in the same language.