Allow updating single fields in solr

This commit is contained in:
Eike Kettner 2020-06-20 23:37:47 +02:00
parent 1f4ff0d4c4
commit 383614f908
6 changed files with 80 additions and 29 deletions

View File

@ -1,6 +1,7 @@
package docspell.ftssolr
import io.circe._
import docspell.common._
final class Field(val name: String) extends AnyVal {
@ -12,19 +13,25 @@ object Field {
def apply(name: String): Field =
new Field(name)
val id = Field("id")
val itemId = Field("itemId")
val collectiveId = Field("collectiveId")
val attachmentId = Field("attachmentId")
val discriminator = Field("discriminator")
val id = Field("id")
val itemId = Field("itemId")
val collectiveId = Field("collectiveId")
val attachmentId = Field("attachmentId")
val discriminator = Field("discriminator")
val attachmentName = Field("attachmentName")
val content = Field("content")
val content_de = Field("content_de")
val content_en = Field("content_en")
val itemName = Field("itemName")
val itemNotes = Field("itemNotes")
val content = Field("content")
val content_de = Field("content_de")
val content_en = Field("content_en")
val itemName = Field("itemName")
val itemNotes = Field("itemNotes")
def contentField(lang: Language): Field =
lang match {
case Language.German =>
Field.content_de
case Language.English =>
Field.content_en
}
implicit val jsonEncoder: Encoder[Field] =
Encoder.encodeString.contramap(_.name)

View File

@ -1,6 +1,7 @@
package docspell.ftssolr
import io.circe._
import io.circe.syntax._
import docspell.common._
import docspell.ftsclient._
@ -12,15 +13,7 @@ trait JsonCodec {
new Encoder[TextData.Attachment] {
final def apply(td: TextData.Attachment): Json = {
val cnt =
(
td.lang match {
case Language.German =>
Field.content_de.name
case Language.English =>
Field.content_en.name
},
Json.fromString(td.text.getOrElse(""))
)
(Field.contentField(td.lang).name, Json.fromString(td.text.getOrElse("")))
Json.fromFields(
cnt :: List(
@ -100,6 +93,41 @@ trait JsonCodec {
new KeyDecoder[Ident] {
override def apply(ident: String): Option[Ident] = Ident(ident).toOption
}
def setAttachmentEncoder(implicit
enc: Encoder[Ident]
): Encoder[TextData.Attachment] =
new Encoder[TextData.Attachment] {
final def apply(td: TextData.Attachment): Json = {
val setter = List(
td.name.map(n => (Field.attachmentName.name, Map("set" -> n.asJson).asJson)),
td.text.map(txt =>
(Field.contentField(td.lang).name, Map("set" -> txt.asJson).asJson)
)
).flatten
Json.fromFields(
(Field.id.name, enc(td.id)) :: setter
)
}
}
def setItemEncoder(implicit enc: Encoder[Ident]): Encoder[TextData.Item] =
new Encoder[TextData.Item] {
final def apply(td: TextData.Item): Json = {
val setter = List(
td.name.map(n => (Field.itemName.name, Map("set" -> n.asJson).asJson)),
td.notes.map(n => (Field.itemNotes.name, Map("set" -> n.asJson).asJson))
).flatten
Json.fromFields(
(Field.id.name, enc(td.id)) :: setter
)
}
}
implicit def textDataEncoder: Encoder[SetFields] =
Encoder(_.td.fold(setAttachmentEncoder.apply, setItemEncoder.apply))
}
object JsonCodec extends JsonCodec

View File

@ -0,0 +1,5 @@
package docspell.ftssolr
import docspell.ftsclient._
final case class SetFields(td: TextData)

View File

@ -24,7 +24,7 @@ final class SolrFtsClient[F[_]: Effect](
(for {
_ <- Stream.eval(logger.debug("Inserting data into index"))
chunks <- data.chunks
res <- Stream.eval(solrUpdate.many(chunks.toList).attempt)
res <- Stream.eval(solrUpdate.add(chunks.toList).attempt)
_ <- res match {
case Right(()) => Stream.emit(())
case Left(ex) =>

View File

@ -82,7 +82,9 @@ object SolrSetup {
}
}
// Schema Commands
// Schema Commands: The structure is for conveniently creating the
// solr json. All fields must be stored, because of highlighting and
// single-updates only work when all fields are stored.
case class AddField(
name: Field,

View File

@ -14,9 +14,9 @@ import JsonCodec._
trait SolrUpdate[F[_]] {
def single(td: TextData): F[Unit]
def add(tds: List[TextData]): F[Unit]
def many(tds: List[TextData]): F[Unit]
def update(tds: List[TextData]): F[Unit]
}
@ -33,15 +33,24 @@ object SolrUpdate {
.withQueryParam("overwrite", "true")
.withQueryParam("wt", "json")
def single(td: TextData): F[Unit] = {
val req = Method.POST(td.asJson, url)
client.expect[String](req).map(r => logger.debug(s"Req: $req Response: $r"))
}
def many(tds: List[TextData]): F[Unit] = {
def add(tds: List[TextData]): F[Unit] = {
val req = Method.POST(tds.asJson, url)
client.expect[String](req).map(r => logger.debug(s"Req: $req Response: $r"))
}
def update(tds: List[TextData]): F[Unit] = {
val req = Method.POST(tds.filter(minOneChange).map(SetFields).asJson, url)
client.expect[String](req).map(r => logger.debug(s"Req: $req Response: $r"))
}
private val minOneChange: TextData => Boolean =
_ match {
case td: TextData.Attachment =>
td.name.isDefined || td.text.isDefined
case td: TextData.Item =>
td.name.isDefined || td.notes.isDefined
}
}
}
}