<commit_before>package com.azavea.rf.database.filter

import java.sql.Timestamp
import java.util.UUID

import com.azavea.rf.database.meta.RFMeta
import com.azavea.rf.database.Filterable
import com.azavea.rf.datamodel._
import cats.implicits._
import doobie._
import doobie.implicits._
import doobie.Fragments.in
import doobie.postgres._
import doobie.postgres.implicits._
import cats._
import cats.data._
import cats.effect.IO
import geotrellis.slick.Projected
import geotrellis.vector._

import com.typesafe.scalalogging.LazyLogging

trait Filterables extends RFMeta with LazyLogging {

  implicit val aoiQueryParamsFilter = Filterable[Any, AoiQueryParameters] { qp: AoiQueryParameters =>
      Filters.userQP(qp.userParams) ++
      Filters.timestampQP(qp.timestampParams)
  }

  implicit val permissionsFilter = Filterable[Any, User] { user: User =>
    val filter = Some(fr"owner = ${user.id}")
    List(filter)
  }

  implicit val orgFilters = Filterable[Any, List[UUID]] { orgIds: List[UUID] =>
    val f1: Option[doobie.Fragment] = orgIds.toNel.map(ids => in(fr"organization_id", ids))
    List(f1)
  }

  implicit val userQueryParamsFilter = Filterable[Any, UserQueryParameters] { userParams: UserQueryParameters =>
    Filters.userQP(userParams)
  }

  implicit val orgQueryParamsFilter = Filterable[Any, OrgQueryParameters] { orgParams: OrgQueryParameters =>
    Filters.organizationQP(orgParams)
  }

  implicit val timestampQueryParamsFilter = Filterable[Any, TimestampQueryParameters] { tsParams: TimestampQueryParameters =>
    Filters.timestampQP(tsParams)
  }

  implicit val imageQueryparamsFilter = Filterable[Any, ImageQueryParameters] { imgParams: ImageQueryParameters =>
    Filters.imageQP(imgParams)
  }

  implicit val projectQueryParametersFilter = Filterable[Any, ProjectQueryParameters] { projectParams: ProjectQueryParameters =>
    Filters.timestampQP(projectParams.timestampParams) ++
      Filters.userQP(projectParams.userParams) ++
      Filters.searchQP(projectParams.searchParams, List("name"))
  }

  implicit val CombinedToolQueryParametersFilter = Filterable[Any, CombinedToolQueryParameters] { toolParams: CombinedToolQueryParameters =>
    Filters.timestampQP(toolParams.timestampParams) ++
      Filters.userQP(toolParams.userParams) ++
      Filters.searchQP(toolParams.searchParams, List("title", "description"))
  }

  implicit val annotationQueryparamsFilter = Filterable[Any, AnnotationQueryParameters] { annotParams: AnnotationQueryParameters =>
    Filters.userQP(annotParams.userParams) ++ List(
      annotParams.label.map({ label => fr"label = $label" }),
      annotParams.machineGenerated.map({ mg => fr"machine_generated = $mg" }),
      annotParams.minConfidence.map({ minc => fr"min_confidence = $minc" }),
      annotParams.maxConfidence.map({ maxc => fr"max_confidence = $maxc" }),
      annotParams.quality.map({ quality => fr"quality = $quality" }),
      annotParams.annotationGroup.map({ ag => fr"annotation_group = $ag" })
    )
  }

  implicit val combinedSceneQueryParams = Filterable[Any, CombinedSceneQueryParams] { combineSceneParams: CombinedSceneQueryParams =>
    val sceneParams = combineSceneParams.sceneParams
    Filters.userQP(combineSceneParams.userParams) ++
    Filters.timestampQP(combineSceneParams.timestampParams) ++
      List(
        sceneParams.maxCloudCover.map({ mcc => fr"cloud_cover <= $mcc" }),
        sceneParams.minCloudCover.map({ mcc => fr"cloud_cover >= $mcc" }),
        sceneParams.minAcquisitionDatetime.map({ mac => fr"acquisition_date >= $mac" }),
        sceneParams.maxAcquisitionDatetime.map({ mac => fr"acquisition_date <= $mac" }),
        sceneParams.datasource.toList.toNel.map({ds => Fragments.in(fr"datasource", ds) }),
        sceneParams.month.toList.toNel.map(
          { months => Fragments.in(fr"date_part('month', acquisition_date)", months) }
        ),
        sceneParams.minDayOfMonth.map(
          { day => fr"date_part('day', acquisition_date) >= $day" }
        ),
        sceneParams.maxDayOfMonth.map(
          { day => fr"date_part('day', acquisition_date) >= $day" }
        ),
        sceneParams.maxSunAzimuth.map({ msa => fr"sun_azimuth <= ${msa}" }),
        sceneParams.minSunAzimuth.map({ msa => fr"sun_azimuth >= ${msa}" }),
        sceneParams.maxSunElevation.map({ mse => fr"sun_elevation <= ${mse}" }),
        sceneParams.minSunElevation.map({ mse => fr"sun_elevation >= ${mse}" }),
        sceneParams.ingested.map({
          case true => fr"ingest_status = 'INGESTED'"
          case _ => fr"ingest_status != 'INGESTED'"
        }),
        sceneParams.ingestStatus.toList.toNel.map({
          statuses => Fragments.in(fr"ingest_status", statuses)
        }),
        (sceneParams.bboxPolygon, sceneParams.shape) match {
          case (_, Some(shpId)) => None
          case (Some(bboxPolygons), _) => {
            val fragments = bboxPolygons.map(bbox =>
              fr"ST_Intersects(data_footprint, ${bbox})")
            Some(fr"(" ++ Fragments.or(fragments: _*) ++ fr")")
          }
          case _ => None
        }
      )
  }<commit_msg>Prevent use of data_footprint index in scene query<commit_after>package com.azavea.rf.database.filter

import java.sql.Timestamp
import java.util.UUID

import com.azavea.rf.database.meta.RFMeta
import com.azavea.rf.database.Filterable
import com.azavea.rf.datamodel._
import cats.implicits._
import doobie._
import doobie.implicits._
import doobie.Fragments.in
import doobie.postgres._
import doobie.postgres.implicits._
import cats._
import cats.data._
import cats.effect.IO
import geotrellis.slick.Projected
import geotrellis.vector._

import com.typesafe.scalalogging.LazyLogging

trait Filterables extends RFMeta with LazyLogging {

  implicit val aoiQueryParamsFilter = Filterable[Any, AoiQueryParameters] { qp: AoiQueryParameters =>
      Filters.userQP(qp.userParams) ++
      Filters.timestampQP(qp.timestampParams)
  }

  implicit val permissionsFilter = Filterable[Any, User] { user: User =>
    val filter = Some(fr"owner = ${user.id}")
    List(filter)
  }

  implicit val orgFilters = Filterable[Any, List[UUID]] { orgIds: List[UUID] =>
    val f1: Option[doobie.Fragment] = orgIds.toNel.map(ids => in(fr"organization_id", ids))
    List(f1)
  }

  implicit val userQueryParamsFilter = Filterable[Any, UserQueryParameters] { userParams: UserQueryParameters =>
    Filters.userQP(userParams)
  }

  implicit val orgQueryParamsFilter = Filterable[Any, OrgQueryParameters] { orgParams: OrgQueryParameters =>
    Filters.organizationQP(orgParams)
  }

  implicit val timestampQueryParamsFilter = Filterable[Any, TimestampQueryParameters] { tsParams: TimestampQueryParameters =>
    Filters.timestampQP(tsParams)
  }

  implicit val imageQueryparamsFilter = Filterable[Any, ImageQueryParameters] { imgParams: ImageQueryParameters =>
    Filters.imageQP(imgParams)
  }

  implicit val projectQueryParametersFilter = Filterable[Any, ProjectQueryParameters] { projectParams: ProjectQueryParameters =>
    Filters.timestampQP(projectParams.timestampParams) ++
      Filters.userQP(projectParams.userParams) ++
      Filters.searchQP(projectParams.searchParams, List("name"))
  }

  implicit val CombinedToolQueryParametersFilter = Filterable[Any, CombinedToolQueryParameters] { toolParams: CombinedToolQueryParameters =>
    Filters.timestampQP(toolParams.timestampParams) ++
      Filters.userQP(toolParams.userParams) ++
      Filters.searchQP(toolParams.searchParams, List("title", "description"))
  }

  implicit val annotationQueryparamsFilter = Filterable[Any, AnnotationQueryParameters] { annotParams: AnnotationQueryParameters =>
    Filters.userQP(annotParams.userParams) ++ List(
      annotParams.label.map({ label => fr"label = $label" }),
      annotParams.machineGenerated.map({ mg => fr"machine_generated = $mg" }),
      annotParams.minConfidence.map({ minc => fr"min_confidence = $minc" }),
      annotParams.maxConfidence.map({ maxc => fr"max_confidence = $maxc" }),
      annotParams.quality.map({ quality => fr"quality = $quality" }),
      annotParams.annotationGroup.map({ ag => fr"annotation_group = $ag" })
    )
  }

  implicit val combinedSceneQueryParams = Filterable[Any, CombinedSceneQueryParams] { combineSceneParams: CombinedSceneQueryParams =>
    val sceneParams = combineSceneParams.sceneParams
    Filters.userQP(combineSceneParams.userParams) ++
    Filters.timestampQP(combineSceneParams.timestampParams) ++
      List(
        sceneParams.maxCloudCover.map({ mcc => fr"cloud_cover <= $mcc" }),
        sceneParams.minCloudCover.map({ mcc => fr"cloud_cover >= $mcc" }),
        sceneParams.minAcquisitionDatetime.map({ mac => fr"acquisition_date >= $mac" }),
        sceneParams.maxAcquisitionDatetime.map({ mac => fr"acquisition_date <= $mac" }),
        sceneParams.datasource.toList.toNel.map({ds => Fragments.in(fr"datasource", ds) }),
        sceneParams.month.toList.toNel.map(
          { months => Fragments.in(fr"date_part('month', acquisition_date)", months) }
        ),
        sceneParams.minDayOfMonth.map(
          { day => fr"date_part('day', acquisition_date) >= $day" }
        ),
        sceneParams.maxDayOfMonth.map(
          { day => fr"date_part('day', acquisition_date) >= $day" }
        ),
        sceneParams.maxSunAzimuth.map({ msa => fr"sun_azimuth <= ${msa}" }),
        sceneParams.minSunAzimuth.map({ msa => fr"sun_azimuth >= ${msa}" }),
        sceneParams.maxSunElevation.map({ mse => fr"sun_elevation <= ${mse}" }),
        sceneParams.minSunElevation.map({ mse => fr"sun_elevation >= ${mse}" }),
        sceneParams.ingested.map({
          case true => fr"ingest_status = 'INGESTED'"
          case _ => fr"ingest_status != 'INGESTED'"
        }),
        sceneParams.ingestStatus.toList.toNel.map({
          statuses => Fragments.in(fr"ingest_status", statuses)
        }),
        (sceneParams.bboxPolygon, sceneParams.shape) match {
          case (_, Some(shpId)) => None
          case (Some(bboxPolygons), _) => {
            val fragments = bboxPolygons.map(bbox =>
              fr"(_ST_Intersects(data_footprint, ${bbox}) AND tile_footprint && ${bbox})")
            Some(fr"(" ++ Fragments.or(fragments: _*) ++ fr")")
          }
          case _ => None
        }
      )
  }
{'fraction_non_alphanumeric': 0.12577942322681215, 'fraction_numerical': 0.0003897116134060795, 'mean_word_length': 3.9256238003838773, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5046794', 'n_tokens_mistral': 3227, 'n_tokens_neox': 3165, 'n_words': 526}