mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 10:28:27 +00:00
216 lines
7.0 KiB
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
|