Files
docspell/modules/fts-solr/src/main/scala/docspell/ftssolr/JsonCodec.scala

216 lines
7.0 KiB
Scala

/*
* Copyright 2020 Eike K. & Contributors
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package docspell.ftssolr
import cats.implicits._
import docspell.common._
import docspell.ftsclient._
import io.circe._
import io.circe.syntax._
trait JsonCodec {
implicit def attachmentEncoder(implicit
enc: Encoder[Ident],
encCid: Encoder[CollectiveId]
): Encoder[TextData.Attachment] =
new Encoder[TextData.Attachment] {
final def apply(td: TextData.Attachment): Json = {
val cnt =
(Field.contentField(td.language).name, Json.fromString(td.text.getOrElse("")))
Json.fromFields(
cnt :: List(
(Field.id.name, enc(td.id)),
(Field.itemId.name, enc(td.item)),
(Field.collectiveId.name, encCid(td.collective)),
(Field.folderId.name, td.folder.getOrElse(Ident.unsafe("")).asJson),
(Field.attachmentId.name, enc(td.attachId)),
(Field.attachmentName.name, Json.fromString(td.name.getOrElse(""))),
(Field.discriminator.name, Json.fromString("attachment"))
)
)
}
}
implicit def itemEncoder(implicit
enc: Encoder[Ident],
encCid: Encoder[CollectiveId]
): Encoder[TextData.Item] =
new Encoder[TextData.Item] {
final def apply(td: TextData.Item): Json =
Json.obj(
(Field.id.name, enc(td.id)),
(Field.itemId.name, enc(td.item)),
(Field.collectiveId.name, encCid(td.collective)),
(Field.folderId.name, td.folder.getOrElse(Ident.unsafe("")).asJson),
(Field.itemName.name, Json.fromString(td.name.getOrElse(""))),
(Field.itemNotes.name, Json.fromString(td.notes.getOrElse(""))),
(Field.discriminator.name, Json.fromString("item"))
)
}
implicit def textDataEncoder(implicit
ae: Encoder[TextData.Attachment],
ie: Encoder[TextData.Item]
): Encoder[TextData] =
Encoder(_.fold(ae.apply, ie.apply))
implicit def versionDocEncoder: Encoder[VersionDoc] =
new Encoder[VersionDoc] {
final def apply(d: VersionDoc): Json =
Json.fromFields(
List(
(VersionDoc.Fields.id.name, d.id.asJson),
(
VersionDoc.Fields.currentVersion.name,
Map("set" -> d.currentVersion.asJson).asJson
)
)
)
}
implicit def decoderVersionDoc: Decoder[VersionDoc] =
new Decoder[VersionDoc] {
final def apply(c: HCursor): Decoder.Result[VersionDoc] =
for {
id <- c.get[String](VersionDoc.Fields.id.name)
version <- c.get[Int](VersionDoc.Fields.currentVersion.name)
} yield VersionDoc(id, version)
}
implicit def versionDocDecoder: Decoder[Option[VersionDoc]] =
new Decoder[Option[VersionDoc]] {
final def apply(c: HCursor): Decoder.Result[Option[VersionDoc]] =
c.downField("response")
.get[List[VersionDoc]]("docs")
.map(_.headOption)
}
implicit def docIdResultsDecoder: Decoder[DocIdResult] =
new Decoder[DocIdResult] {
final def apply(c: HCursor): Decoder.Result[DocIdResult] =
c.downField("response")
.downField("docs")
.values
.getOrElse(Nil)
.toList
.traverse(_.hcursor.get[Ident](Field.id.name))
.map(DocIdResult.apply)
}
implicit def ftsResultDecoder: Decoder[FtsResult] =
new Decoder[FtsResult] {
final def apply(c: HCursor): Decoder.Result[FtsResult] =
for {
qtime <- c.downField("responseHeader").get[Duration]("QTime")
count <- c.downField("response").get[Int]("numFound")
maxScore <- c.downField("response").get[Double]("maxScore")
results <- c.downField("response").get[List[FtsResult.ItemMatch]]("docs")
highlightng <- c.get[Map[Ident, Map[String, List[String]]]]("highlighting")
highlight = highlightng.map(kv => kv._1 -> kv._2.values.flatten.toList)
} yield FtsResult(qtime, count, maxScore, highlight, results)
}
implicit def decodeItemMatch: Decoder[FtsResult.ItemMatch] =
new Decoder[FtsResult.ItemMatch] {
final def apply(c: HCursor): Decoder.Result[FtsResult.ItemMatch] =
for {
itemId <- c.get[Ident](Field.itemId.name)
id <- c.get[Ident](Field.id.name)
coll <- c.get[CollectiveId](Field.collectiveId.name)
score <- c.get[Double]("score")
md <- decodeMatchData(c)
} yield FtsResult.ItemMatch(id, itemId, coll, score, md)
}
def decodeMatchData: Decoder[FtsResult.MatchData] =
new Decoder[FtsResult.MatchData] {
final def apply(c: HCursor): Decoder.Result[FtsResult.MatchData] =
for {
disc <- c.get[String]("discriminator")
md <-
if ("attachment" == disc)
for {
aId <- c.get[Ident](Field.attachmentId.name)
aName <- c.get[String](Field.attachmentName.name)
} yield FtsResult.AttachmentData(aId, aName)
else Right(FtsResult.ItemData)
} yield md
}
implicit def decodeEverythingToUnit: Decoder[Unit] =
new Decoder[Unit] {
final def apply(c: HCursor): Decoder.Result[Unit] =
Right(())
}
implicit def identKeyEncoder: KeyEncoder[Ident] =
new KeyEncoder[Ident] {
override def apply(ident: Ident): String = ident.id
}
implicit def identKeyDecoder: KeyDecoder[Ident] =
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.language).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 setTextDataFieldsEncoder: Encoder[SetFields] =
Encoder(_.td.fold(setAttachmentEncoder.apply, setItemEncoder.apply))
implicit def setFolderEncoder(implicit
enc: Encoder[Option[Ident]]
): Encoder[SetFolder] =
new Encoder[SetFolder] {
final def apply(td: SetFolder): Json =
Json.fromFields(
List(
(Field.id.name, td.docId.asJson),
(
Field.folderId.name,
Map("set" -> td.folder.asJson).asJson
)
)
)
}
}
object JsonCodec extends JsonCodec