mirror of
				https://github.com/TheAnachronism/docspell.git
				synced 2025-11-04 12:30:12 +00:00 
			
		
		
		
	Add checksum query expr
This commit is contained in:
		@@ -109,7 +109,8 @@ object ItemQuery {
 | 
			
		||||
    final case class CustomFieldIdMatch(id: String, op: Operator, value: String)
 | 
			
		||||
        extends Expr
 | 
			
		||||
 | 
			
		||||
    final case class Fulltext(query: String) extends Expr
 | 
			
		||||
    final case class Fulltext(query: String)         extends Expr
 | 
			
		||||
    final case class ChecksumMatch(checksum: String) extends Expr
 | 
			
		||||
 | 
			
		||||
    // things that can be expressed with terms above
 | 
			
		||||
    sealed trait MacroExpr extends Expr {
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,8 @@ object ExprUtil {
 | 
			
		||||
        expr
 | 
			
		||||
      case CustomFieldIdMatch(_, _, _) =>
 | 
			
		||||
        expr
 | 
			
		||||
      case ChecksumMatch(_) =>
 | 
			
		||||
        expr
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private def spliceAnd(nodes: Nel[Expr]): Nel[Expr] =
 | 
			
		||||
 
 | 
			
		||||
@@ -76,6 +76,9 @@ object SimpleExprParser {
 | 
			
		||||
  val dirExpr: P[Expr.DirectionExpr] =
 | 
			
		||||
    (P.string("incoming:") *> BasicParser.bool).map(Expr.DirectionExpr.apply)
 | 
			
		||||
 | 
			
		||||
  val checksumExpr: P[Expr.ChecksumMatch] =
 | 
			
		||||
    (P.string("checksum:") *> BasicParser.singleString).map(Expr.ChecksumMatch.apply)
 | 
			
		||||
 | 
			
		||||
  val simpleExpr: P[Expr] =
 | 
			
		||||
    P.oneOf(
 | 
			
		||||
      List(
 | 
			
		||||
@@ -89,7 +92,8 @@ object SimpleExprParser {
 | 
			
		||||
        customFieldIdExpr,
 | 
			
		||||
        customFieldExpr,
 | 
			
		||||
        inboxExpr,
 | 
			
		||||
        dirExpr
 | 
			
		||||
        dirExpr,
 | 
			
		||||
        checksumExpr
 | 
			
		||||
      )
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,15 +3,16 @@ package docspell.store.qb.generator
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.time.LocalDate
 | 
			
		||||
 | 
			
		||||
import cats.data.NonEmptyList
 | 
			
		||||
import cats.data.{NonEmptyList => Nel}
 | 
			
		||||
 | 
			
		||||
import docspell.common._
 | 
			
		||||
import docspell.query.ItemQuery._
 | 
			
		||||
import docspell.query.{Date, ItemQuery}
 | 
			
		||||
import docspell.store.qb.DSL._
 | 
			
		||||
import docspell.store.qb.{Operator => QOp, _}
 | 
			
		||||
import docspell.store.queries.QItem
 | 
			
		||||
import docspell.store.queries.QueryWildcard
 | 
			
		||||
import docspell.store.records.{RCustomField, RCustomFieldValue, TagItemName}
 | 
			
		||||
import docspell.store.records._
 | 
			
		||||
 | 
			
		||||
import doobie.util.Put
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +40,7 @@ object ItemQueryGenerator {
 | 
			
		||||
 | 
			
		||||
          case Expr.TagIdsMatch(op, tags) =>
 | 
			
		||||
            val ids = tags.toList.flatMap(s => Ident.fromString(s).toOption)
 | 
			
		||||
            NonEmptyList
 | 
			
		||||
            Nel
 | 
			
		||||
              .fromList(ids)
 | 
			
		||||
              .map { nel =>
 | 
			
		||||
                op match {
 | 
			
		||||
@@ -114,7 +115,7 @@ object ItemQueryGenerator {
 | 
			
		||||
 | 
			
		||||
      case Expr.TagIdsMatch(op, tags) =>
 | 
			
		||||
        val ids = tags.toList.flatMap(s => Ident.fromString(s).toOption)
 | 
			
		||||
        NonEmptyList
 | 
			
		||||
        Nel
 | 
			
		||||
          .fromList(ids)
 | 
			
		||||
          .map { nel =>
 | 
			
		||||
            op match {
 | 
			
		||||
@@ -152,6 +153,10 @@ object ItemQueryGenerator {
 | 
			
		||||
      case Expr.CustomFieldIdMatch(field, op, value) =>
 | 
			
		||||
        tables.item.id.in(itemsWithCustomField(_.id ==== field)(coll, makeOp(op), value))
 | 
			
		||||
 | 
			
		||||
      case Expr.ChecksumMatch(checksum) =>
 | 
			
		||||
        val select = QItem.findByChecksumQuery(checksum, coll, Set.empty)
 | 
			
		||||
        tables.item.id.in(select.withSelect(Nel.of(RItem.as("i").id.s)))
 | 
			
		||||
 | 
			
		||||
      case Expr.Fulltext(_) =>
 | 
			
		||||
        // not supported here
 | 
			
		||||
        Condition.unit
 | 
			
		||||
 
 | 
			
		||||
@@ -509,6 +509,16 @@ object QItem {
 | 
			
		||||
      collective: Ident,
 | 
			
		||||
      excludeFileMeta: Set[Ident]
 | 
			
		||||
  ): ConnectionIO[Vector[RItem]] = {
 | 
			
		||||
    val qq = findByChecksumQuery(checksum, collective, excludeFileMeta).build
 | 
			
		||||
    logger.debug(s"FindByChecksum: $qq")
 | 
			
		||||
    qq.query[RItem].to[Vector]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  def findByChecksumQuery(
 | 
			
		||||
      checksum: String,
 | 
			
		||||
      collective: Ident,
 | 
			
		||||
      excludeFileMeta: Set[Ident]
 | 
			
		||||
  ): Select = {
 | 
			
		||||
    val m1  = RFileMeta.as("m1")
 | 
			
		||||
    val m2  = RFileMeta.as("m2")
 | 
			
		||||
    val m3  = RFileMeta.as("m3")
 | 
			
		||||
@@ -517,26 +527,23 @@ object QItem {
 | 
			
		||||
    val s   = RAttachmentSource.as("s")
 | 
			
		||||
    val r   = RAttachmentArchive.as("r")
 | 
			
		||||
    val fms = Nel.of(m1, m2, m3)
 | 
			
		||||
    val qq =
 | 
			
		||||
      Select(
 | 
			
		||||
        select(i.all),
 | 
			
		||||
        from(i)
 | 
			
		||||
          .innerJoin(a, a.itemId === i.id)
 | 
			
		||||
          .innerJoin(s, s.id === a.id)
 | 
			
		||||
          .innerJoin(m1, m1.id === a.fileId)
 | 
			
		||||
          .innerJoin(m2, m2.id === s.fileId)
 | 
			
		||||
          .leftJoin(r, r.id === a.id)
 | 
			
		||||
          .leftJoin(m3, m3.id === r.fileId),
 | 
			
		||||
        where(
 | 
			
		||||
          i.cid === collective &&
 | 
			
		||||
            Condition.Or(fms.map(m => m.checksum === checksum)) &&?
 | 
			
		||||
            Nel
 | 
			
		||||
              .fromList(excludeFileMeta.toList)
 | 
			
		||||
              .map(excl => Condition.And(fms.map(m => m.id.isNull || m.id.notIn(excl))))
 | 
			
		||||
        )
 | 
			
		||||
      ).distinct.build
 | 
			
		||||
    logger.debug(s"FindByChecksum: $qq")
 | 
			
		||||
    qq.query[RItem].to[Vector]
 | 
			
		||||
    Select(
 | 
			
		||||
      select(i.all),
 | 
			
		||||
      from(i)
 | 
			
		||||
        .innerJoin(a, a.itemId === i.id)
 | 
			
		||||
        .innerJoin(s, s.id === a.id)
 | 
			
		||||
        .innerJoin(m1, m1.id === a.fileId)
 | 
			
		||||
        .innerJoin(m2, m2.id === s.fileId)
 | 
			
		||||
        .leftJoin(r, r.id === a.id)
 | 
			
		||||
        .leftJoin(m3, m3.id === r.fileId),
 | 
			
		||||
      where(
 | 
			
		||||
        i.cid === collective &&
 | 
			
		||||
          Condition.Or(fms.map(m => m.checksum === checksum)) &&?
 | 
			
		||||
          Nel
 | 
			
		||||
            .fromList(excludeFileMeta.toList)
 | 
			
		||||
            .map(excl => Condition.And(fms.map(m => m.id.isNull || m.id.notIn(excl))))
 | 
			
		||||
      )
 | 
			
		||||
    ).distinct
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final case class NameAndNotes(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user