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

refactor(v3): add project slice (DEV-1009) #2076

Merged
merged 82 commits into from Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from 78 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
6cf00e5
chore: create SBT project
BalduinLandolt Jun 13, 2022
a975458
chore: set up files and folders for all the layers
BalduinLandolt Jun 13, 2022
9a0d691
reasonably implement project domain
BalduinLandolt Jun 13, 2022
35d5ca0
test: add tests for ProjectDomain
BalduinLandolt Jun 13, 2022
69eba6e
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Jun 21, 2022
b4613fb
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Jul 27, 2022
1b88e60
fix wrongly resolved merge conflict
BalduinLandolt Jul 27, 2022
3e87563
add user repo interface
BalduinLandolt Jul 27, 2022
0b50eee
feat:pretty much finish project.core part plus add some stuff in shar…
BalduinLandolt Jul 27, 2022
ce96612
mark TODOs as mine
BalduinLandolt Jul 28, 2022
b52c7d2
fix: missed some renaming
BalduinLandolt Jul 28, 2022
f919e18
fix: another oversight
BalduinLandolt Jul 28, 2022
be6c6a1
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Aug 3, 2022
60db8ca
introduce the concept of multi-lang-strings
BalduinLandolt Aug 3, 2022
97be69c
add docstring
BalduinLandolt Aug 3, 2022
52db9ed
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Aug 3, 2022
687d456
delete test for interface
BalduinLandolt Aug 4, 2022
2db42ff
add in-memory implementation for user repo
BalduinLandolt Aug 4, 2022
65595b2
add tests for user repo mock
BalduinLandolt Aug 4, 2022
2ada1ec
add (dummy) live repo implementation
BalduinLandolt Aug 4, 2022
b82367b
actually log in unsafeMake despite ZIO logging in non-ZIO context
BalduinLandolt Aug 4, 2022
2537419
fix small error from merge conflict
BalduinLandolt Aug 8, 2022
53abeab
implement project handler
BalduinLandolt Aug 8, 2022
89185d6
fix issue with repo
BalduinLandolt Aug 8, 2022
b0905a1
add test for project handler
BalduinLandolt Aug 8, 2022
638092a
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Aug 8, 2022
b9e683f
rename value objects
BalduinLandolt Aug 8, 2022
000bcc4
rename stuff
BalduinLandolt Aug 8, 2022
4375df5
fix after renaming
BalduinLandolt Aug 8, 2022
5d92ed5
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Aug 8, 2022
fe79ab8
make test for sorting projects more deterministic
BalduinLandolt Aug 9, 2022
2ef8c9a
add role and project tests to makefile; improve makefile structure
BalduinLandolt Aug 9, 2022
7128750
add role and user slice to root project
BalduinLandolt Aug 9, 2022
c2802ed
use more value objects
BalduinLandolt Aug 9, 2022
9e447c6
use more valueobjects
BalduinLandolt Aug 9, 2022
3b764ee
clean up more tests
BalduinLandolt Aug 9, 2022
713fb44
specify some TODO comments
BalduinLandolt Aug 9, 2022
33cd01a
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Aug 10, 2022
53030b0
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Aug 29, 2022
39a0a68
fix build.sbt
BalduinLandolt Aug 29, 2022
82aec62
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Aug 29, 2022
5c32e4f
reformat files
BalduinLandolt Aug 29, 2022
7808c7a
add schema slice test to make file
BalduinLandolt Aug 29, 2022
e7bf43d
fix build.sbt even more
BalduinLandolt Aug 29, 2022
1936b08
fix again
BalduinLandolt Aug 29, 2022
f73b506
get rid of warnings
BalduinLandolt Aug 29, 2022
15ca624
add update methods to project handler
BalduinLandolt Aug 29, 2022
ae25998
format imports
BalduinLandolt Aug 29, 2022
1dc8981
remove codesmells
BalduinLandolt Aug 29, 2022
2c40a0b
improve project creation
BalduinLandolt Aug 29, 2022
88ca294
fix code smell
BalduinLandolt Aug 29, 2022
a58dfe2
fix lower case shortcodes
BalduinLandolt Aug 30, 2022
715c70a
format files
BalduinLandolt Aug 30, 2022
c2b6599
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Sep 1, 2022
7d08a44
hopefully remove code smell
BalduinLandolt Sep 1, 2022
b80482d
reduce code smells
BalduinLandolt Sep 1, 2022
213fea6
remove code smells
BalduinLandolt Sep 1, 2022
fc6d829
improve handler API
BalduinLandolt Sep 1, 2022
7086a36
fix handler API
BalduinLandolt Sep 1, 2022
c858cf7
tidy up
BalduinLandolt Sep 1, 2022
cd93852
create project in handler from value object instead of components
BalduinLandolt Sep 1, 2022
96dff72
tidy up
BalduinLandolt Sep 1, 2022
2fd4980
improve code readability
BalduinLandolt Sep 1, 2022
6cfca38
fix formatting issue
BalduinLandolt Sep 1, 2022
858246d
add methods to MultiLangString
BalduinLandolt Sep 1, 2022
3b0740e
make validations use validationexception
BalduinLandolt Sep 5, 2022
079a43e
fix tests accordingly
BalduinLandolt Sep 5, 2022
a377ee4
add comment
BalduinLandolt Sep 5, 2022
ab75e12
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Sep 5, 2022
b5e2453
improve test structure by using top level suites
BalduinLandolt Sep 5, 2022
3a85f95
minor refactoring
BalduinLandolt Sep 5, 2022
11c8240
Merge branch 'main' into wip/DEV-1009-create-project-slice
BalduinLandolt Sep 7, 2022
f987561
remove redundantly provided layers
BalduinLandolt Sep 7, 2022
b9ff62d
improve test implementation of project repo
BalduinLandolt Sep 7, 2022
f27849e
test test functionality
BalduinLandolt Sep 7, 2022
c824912
cleanup
BalduinLandolt Sep 7, 2022
dc87dde
clean up
BalduinLandolt Sep 7, 2022
fe06f3f
Update Makefile
BalduinLandolt Sep 7, 2022
b096432
add review feedback
BalduinLandolt Sep 8, 2022
af52705
add review feedback
BalduinLandolt Sep 8, 2022
2d70fc1
add review feedback
BalduinLandolt Sep 8, 2022
961c593
remove update functionality from MultiLangString
BalduinLandolt Sep 8, 2022
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
26 changes: 25 additions & 1 deletion Makefile
Expand Up @@ -202,15 +202,39 @@ test-repository-upgrade: build init-db-test-minimal ## runs DB upgrade integrati
@$(MAKE) -f $(THIS_FILE) stack-up

.PHONY: test
test: build ## runs all tests
test: build test-shared test-user-slice test-role-slice test-project-slice ## runs all tests
sbt -v coverage "webapi/test"
sbt -v coverage "schemaCore/test"
sbt coverageAggregate

.PHONY: test-shared
test-shared: ## tests the shared projects (build is not called from this target)
sbt -v coverage "shared/test"

.PHONY: test-user-slice
test-user-slice: ## tests all projects relating to the user slice (build is not called from this target)
sbt -v coverage "userCore/test"
sbt -v coverage "userHandler/test"
sbt -v coverage "userInterface/test"
sbt -v coverage "userRepo/test"
sbt coverageAggregate

.PHONY: test-role-slice
test-role-slice: ## tests all projects relating to the role slice (build is not called from this target)
sbt -v coverage "roleCore/test"
sbt -v coverage "roleHandler/test"
sbt -v coverage "roleInterface/test"
sbt -v coverage "roleRepo/test"
sbt coverageAggregate

.PHONY: test-project-slice
test-project-slice: ## tests all projects relating to the project slice (build is not called from this target)
sbt -v coverage "projectCore/test"
sbt -v coverage "projectHandler/test"
sbt -v coverage "projectInterface/test"
sbt -v coverage "projectRepo/test"
sbt coverageAggregate


#################################
## Database Management
Expand Down
56 changes: 55 additions & 1 deletion build.sbt
Expand Up @@ -37,14 +37,22 @@ lazy val root: Project = Project(id = "root", file("."))
webapi,
sipi,
shared,
// user
userCore,
userHandler,
userRepo,
userInterface,
// role
roleCore,
roleRepo,
roleHandler,
roleRepo,
roleInterface,
// project
projectCore,
projectHandler,
projectRepo,
projectInterface,
// schema
schemaCore
)
.enablePlugins(GitVersioning, GitBranchPrompt)
Expand Down Expand Up @@ -352,6 +360,52 @@ lazy val userCore = project
)
.dependsOn(shared)

// project projects

lazy val projectInterface = project
.in(file("dsp-project/interface"))
.settings(
scalacOptions ++= customScalacOptions,
name := "projectInterface",
libraryDependencies ++= Dependencies.projectInterfaceLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared, projectHandler)

lazy val projectHandler = project
.in(file("dsp-project/handler"))
.settings(
scalacOptions ++= customScalacOptions,
name := "projectHandler",
libraryDependencies ++= Dependencies.projectHandlerLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(
shared,
projectCore,
projectRepo % "test->test"
) // projectHandler tests need mock implementation of ProjectRepo

lazy val projectCore = project
.in(file("dsp-project/core"))
.settings(
scalacOptions ++= customScalacOptions,
name := "projectCore",
libraryDependencies ++= Dependencies.projectCoreLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared)

lazy val projectRepo = project
.in(file("dsp-project/repo"))
.settings(
scalacOptions ++= customScalacOptions,
name := "projectRepo",
libraryDependencies ++= Dependencies.projectRepoLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared, projectCore)

// schema projects

lazy val schemaCore = project
Expand Down
@@ -0,0 +1,70 @@
/*
* 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.project.api

import zio._
import zio.macros.accessible

import dsp.project.domain._
import dsp.valueobjects.Project._
import dsp.valueobjects._

/**
* The trait (interface) for the project repository. The project repository is responsible for storing and retrieving projects.
* Needs to be used by the project repository implementations.
*/
@accessible // with this annotation we don't have to write the companion object ourselves
trait ProjectRepo {

/**
* Writes a project to the repository (used for both create and update).
* If this fails (e.g. the triplestore is not available), it's a non-recovable error. That's why we need UIO.
* When used, we should do it like: ...store(...).orDie
*
* @param project the project to write
* @return The project ID
*/
def storeProject(project: Project): UIO[ProjectId]

/**
* Gets all projects from the repository.
*
* @return a list of [[Project]]
*/
def getProjects(): UIO[List[Project]]

/**
* Retrieves the project from the repository by ID.
*
* @param id the project's ID
* @return an optional [[Project]]
*/
def getProjectById(id: ProjectId): IO[Option[Nothing], Project]

/**
* Retrieves the project from the repository by ShortCode.
*
* @param shortCode ShortCode of the project.
* @return an optional [[Project]].
*/
def getProjectByShortCode(shortCode: ShortCode): IO[Option[Nothing], Project]

/**
* Checks if a project ShortCode exists in the repo.
*
* @param shortCode ShortCode of the project.
* @return Unit in case of success
*/
def checkShortCodeExists(shortCode: ShortCode): IO[Option[Nothing], Unit]
BalduinLandolt marked this conversation as resolved.
Show resolved Hide resolved

/**
* Deletes a [[Project]] from the repository by its [[ProjectId]].
*
* @param id the project ID
* @return Project ID or None if not found
*/
def deleteProject(id: ProjectId): IO[Option[Nothing], ProjectId]
}
@@ -0,0 +1,68 @@
/*
* Copyright © 2021 - 2022 Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
* SPDX-License-Identifier: Apache-2.0
*/

package dsp.project.domain

import zio.prelude.Validation

import dsp.errors.ValidationException
import dsp.valueobjects.Project._
import dsp.valueobjects._

/**
* Represents the project domain object.
*
* @param id the ID of the project
* @param name the name of the project
* @param description the description of the project
*/
sealed abstract case class Project private (
id: ProjectId,
name: Name,
description: ProjectDescription
// TODO-BL: [domain-model] missing status, shortname, selfjoin
) extends Ordered[Project] { self =>

/**
* Allows to sort collections of [[Project]]s. Sorting is done by the IRI.
*/
def compare(that: Project): Int = self.id.iri.toString().compareTo(that.id.iri.toString())
// TODO-BL: [discuss] by which field should a project be sorted by? shortcode? name? IRI?

/**
* Update the name of the project.
BalduinLandolt marked this conversation as resolved.
Show resolved Hide resolved
*
* @param name the new name
* @return the updated Project
BalduinLandolt marked this conversation as resolved.
Show resolved Hide resolved
*/
def updateProjectName(name: Name): Validation[ValidationException, Project] =
Project.make(
id = self.id,
name = name,
description = self.description
)

/**
* Update the description of the project.
BalduinLandolt marked this conversation as resolved.
Show resolved Hide resolved
*
* @param description the new description
* @return the updated Project
*/
def updateProjectDescription(description: ProjectDescription): Validation[ValidationException, Project] =
Project.make(
id = self.id,
name = self.name,
description = description
)
}
object Project {
def make(
id: ProjectId,
name: Name,
description: ProjectDescription
): Validation[ValidationException, Project] =
Validation.succeed(new Project(id = id, name = name, description = description) {})

}
@@ -0,0 +1,95 @@
/*
* 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.project.domain

import zio.test._

import dsp.valueobjects.Iri
import dsp.valueobjects.Project._
import dsp.valueobjects.ProjectId
import dsp.valueobjects.V2

/**
* This spec is used to test [[dsp.project.domain.ProjectDomain]].
*/
object ProjectDomainSpec extends ZIOSpecDefault {

private val shortcode = ShortCode.make("0001").fold(e => throw e.head, v => v)
private val id = ProjectId.make(shortcode).fold(e => throw e.head, v => v)
private val name = Name.make("proj").fold(e => throw e.head, v => v)
private val description = ProjectDescription
.make(Seq(V2.StringLiteralV2("A Project", Some("en"))))
.fold(e => throw e.head, v => v)

override def spec = suite("ProjectDomainSpec")(
BalduinLandolt marked this conversation as resolved.
Show resolved Hide resolved
projectCreateTests,
projectCompareTests,
projectUpdateTests
)

val projectCreateTests = suite("create project")(
test("create a project from valid input") {
(for {
project <- Project.make(id, name, description)
} yield (
assertTrue(project.id == id) &&
assertTrue(project.name == name) &&
assertTrue(project.description == description)
)).toZIO
}
)

val projectCompareTests = suite("compare projects")(
test("compare projects by IRI") {
val iri1String = s"http://rdfh.ch/projects/d78c6cc8-0a18-4131-af72-4bb6cb688bed"
val iri2String = s"http://rdfh.ch/projects/f4184d7a-caf7-4ab9-991e-d5da9eb7ec17"
(for {
iri1 <- Iri.ProjectIri.make(iri1String)
iri2 <- Iri.ProjectIri.make(iri2String)
id1 <- ProjectId.fromIri(iri1, shortcode)
id2 <- ProjectId.fromIri(iri2, shortcode)
project1 <- Project.make(id1, name, description)
project2 <- Project.make(id2, name, description)
listInitial = List(project1, project2)
listSorted = listInitial.sorted
listSortedInverse = listInitial.sortWith(_ > _)
} yield (
assertTrue(listInitial == listSorted) &&
assertTrue(listInitial != listSortedInverse) &&
assertTrue(listInitial == listSortedInverse.reverse)
)).toZIO
}
)

val projectUpdateTests = suite("update project")(
test("update a project name when provided a valid new name") {
(for {
newName <- Name.make("new project name")
project <- Project.make(id, name, description)
updatedProject <- project.updateProjectName(newName)
} yield (
assertTrue(project.id == updatedProject.id) &&
assertTrue(project.name != updatedProject.name) &&
assertTrue(project.description == updatedProject.description) &&
assertTrue(project.name == name) &&
assertTrue(updatedProject.name == newName)
)).toZIO
},
test("update a project description when provided a valid new description") {
(for {
newDescription <- ProjectDescription.make(Seq(V2.StringLiteralV2("new project name", Some("en"))))
project <- Project.make(id, name, description)
updatedProject <- project.updateProjectDescription(newDescription)
} yield (
assertTrue(project.id == updatedProject.id) &&
assertTrue(project.name == updatedProject.name) &&
assertTrue(project.description != updatedProject.description) &&
assertTrue(project.description == description) &&
assertTrue(updatedProject.description == newDescription)
)).toZIO
}
)
}