/
PredicateObjectMapper.scala
120 lines (108 loc) · 5.1 KB
/
PredicateObjectMapper.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
* Copyright © 2021 - 2023 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
* SPDX-License-Identifier: Apache-2.0
*/
package org.knora.webapi.slice.common.repo.service
import zio._
import dsp.errors.InconsistentRepositoryDataException
import org.knora.webapi.IRI
import org.knora.webapi.messages.store.triplestoremessages.LiteralV2
import org.knora.webapi.messages.store.triplestoremessages.SparqlExtendedConstructResponse.ConstructPredicateObjects
import org.knora.webapi.slice.resourceinfo.domain.IriConverter
/**
* The [[PredicateObjectMapper]] is a service which provides methods to extract values from a [[ConstructPredicateObjects]].
*
* @param iriConverter A service that maps between internal and external IRIs.
*/
final case class PredicateObjectMapper(private val iriConverter: IriConverter) {
/**
* Returns an optional list of values for the given key.
*
* @param key the key to look for.
* @param propertiesMap the map to look in.
* @tparam A the type of the values.
* @return a list of values, [[None]] if key was not present.
* Fails if the value could not be cast to the given type.
*/
def getListOption[A <: LiteralV2](key: IRI, propertiesMap: ConstructPredicateObjects): Task[Option[List[A]]] =
for {
smartIri <- iriConverter.asInternalSmartIri(key)
props = propertiesMap.get(smartIri)
values <- ZIO.foreach(props)(ZIO.foreach(_)(cast[A]).map(_.toList))
} yield values
private def cast[A <: LiteralV2](prop: LiteralV2): Task[A] =
ZIO.attempt(prop.asInstanceOf[A]).logError(s"Could not cast $prop.")
/**
* Returns a list of values for the given key.
* Fails during runtime if the value could not be cast to the given type.
*
* @param key the key to look for.
* @param propertiesMap the map to look in.
* @tparam A the type of the values.
* @return a list of values, an empty list if key was not present or no values are defined.
*/
def getList[A <: LiteralV2](key: IRI, propertiesMap: ConstructPredicateObjects): Task[List[A]] =
getListOption[A](key, propertiesMap).map(_.getOrElse(List.empty[A]))
/**
* Returns a list of values for the given key.
* Fails during runtime if the value could not be cast to the given type.
*
* @param key the key to look for.
* @param propertiesMap the map to look in.
* @tparam A the type of the values.
* @return a list of values, fails with an [[InconsistentRepositoryDataException]] if key was not present.
*/
def getListOrFail[A <: LiteralV2](key: IRI, propertiesMap: ConstructPredicateObjects): Task[List[A]] =
getListOption[A](key, propertiesMap).some
.orElseFail(InconsistentRepositoryDataException(s"PropertiesMap has no $key defined."))
/**
* Returns a [[NonEmptyChunk]] of values for the given key.
* Fails during runtime if the value could not be cast to the given type.
*
* @param key the key to look for.
* @param propertiesMap the map to look in.
* @tparam A the type of the values.
* @return A [[NonEmptyChunk]] of values,
* Fails with an [[InconsistentRepositoryDataException]] if key was not present.
* Fails with an [[InconsistentRepositoryDataException]] if the list of values was empty.
*/
def getNonEmptyChunkOrFail[A <: LiteralV2](
key: IRI,
propertiesMap: ConstructPredicateObjects
): Task[NonEmptyChunk[A]] =
getListOption[A](key, propertiesMap).some
.orElseFail(InconsistentRepositoryDataException(s"PropertiesMap has no $key defined."))
.flatMap(list =>
ZIO
.fail(InconsistentRepositoryDataException(s"PropertiesMap has $key defined but list of values is empty."))
.when(list.isEmpty)
.as(NonEmptyChunk.fromIterable(list.head, list.tail))
)
/**
* Returns an optional single value for the given key.
* Fails during runtime if the value could not be cast to the given type.
*
* @param key the key to look for.
* @param propertiesMap the map to look in.
* @tparam A the type of the values.
* @return a single value, [[None]] if key was not present.
*/
def getSingleOption[A <: LiteralV2](key: IRI, propertiesMap: ConstructPredicateObjects): Task[Option[A]] =
getListOption[A](key, propertiesMap).map(_.flatMap(_.headOption))
/**
* Returns a single value for the given key.
* Fails during runtime if the value could not be cast to the given type.
*
* @param key the key to look for.
* @param propertiesMap the map to look in.
* @tparam A the type of the values.
* @return a single value, fails with an [[InconsistentRepositoryDataException]] if key was not present.
*/
def getSingleOrFail[A <: LiteralV2](key: IRI, propertiesMap: ConstructPredicateObjects): Task[A] =
getSingleOption[A](key, propertiesMap)
.flatMap(ZIO.fromOption(_))
.orElseFail(InconsistentRepositoryDataException(s"PropertiesMap has no value for $key defined."))
}
object PredicateObjectMapper {
val layer: URLayer[IriConverter, PredicateObjectMapper] = ZLayer.fromFunction(PredicateObjectMapper.apply _)
}