aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuicommon/db/PostgresQueryBuilder.scala
blob: 8ef18295f554de0fdeb55413e1a7860afaba2042 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package xyz.driver.pdsuicommon.db

import java.sql.ResultSet

import io.getquill.{PostgresDialect, PostgresEscape}

import scala.collection.breakOut

object PostgresQueryBuilder {

  import xyz.driver.pdsuicommon.db.QueryBuilder._

  type Escape = PostgresEscape
  val Escape = PostgresEscape

  def apply[T](tableName: String,
               lastUpdateFieldName: Option[String],
               nullableFields: Set[String],
               links: Set[TableLink],
               runner: Runner[T],
               countRunner: CountRunner): PostgresQueryBuilder[T] = {
    val parameters = PostgresQueryBuilderParameters(
      tableData = TableData(tableName, lastUpdateFieldName, nullableFields),
      links = links.map(x => x.foreignTableName -> x)(breakOut)
    )
    new PostgresQueryBuilder[T](parameters)(runner, countRunner)
  }

  def apply[T](tableName: String,
               lastUpdateFieldName: Option[String],
               nullableFields: Set[String],
               links: Set[TableLink],
               extractor: ResultSet => T)(implicit sqlContext: PostgresContext): PostgresQueryBuilder[T] = {
    apply(tableName, QueryBuilderParameters.AllFields, lastUpdateFieldName, nullableFields, links, extractor)
  }

  def apply[T](tableName: String,
               fields: Set[String],
               lastUpdateFieldName: Option[String],
               nullableFields: Set[String],
               links: Set[TableLink],
               extractor: ResultSet => T)(implicit sqlContext: PostgresContext): PostgresQueryBuilder[T] = {

    val runner: Runner[T] = { parameters =>
      val (sql, binder) = parameters.toSql(countQuery = false, fields = fields, namingStrategy = PostgresEscape)
      sqlContext.executeQuery[T](sql, binder, { resultSet =>
        extractor(resultSet)
      })
    }

    val countRunner: CountRunner = { parameters =>
      val (sql, binder) = parameters.toSql(countQuery = true, namingStrategy = PostgresEscape)
      sqlContext
        .executeQuery[CountResult](
          sql,
          binder, { resultSet =>
            val count = resultSet.getInt(1)
            val lastUpdate = if (parameters.tableData.lastUpdateFieldName.isDefined) {
              Option(resultSet.getTimestamp(2)).map(sqlContext.timestampToLocalDateTime)
            } else None

            (count, lastUpdate)
          }
        )
        .head
    }

    apply[T](
      tableName = tableName,
      lastUpdateFieldName = lastUpdateFieldName,
      nullableFields = nullableFields,
      links = links,
      runner = runner,
      countRunner = countRunner
    )
  }
}

class PostgresQueryBuilder[T](parameters: PostgresQueryBuilderParameters)(implicit runner: QueryBuilder.Runner[T],
                                                                          countRunner: QueryBuilder.CountRunner)
    extends QueryBuilder[T, PostgresDialect, PostgresQueryBuilder.Escape](parameters) {

  def withFilter(newFilter: SearchFilterExpr): QueryBuilder[T, PostgresDialect, PostgresEscape] = {
    new PostgresQueryBuilder[T](parameters.copy(filter = newFilter))
  }

  def withSorting(newSorting: Sorting): QueryBuilder[T, PostgresDialect, PostgresEscape] = {
    new PostgresQueryBuilder[T](parameters.copy(sorting = newSorting))
  }

  def withPagination(newPagination: Pagination): QueryBuilder[T, PostgresDialect, PostgresEscape] = {
    new PostgresQueryBuilder[T](parameters.copy(pagination = Some(newPagination)))
  }

  def resetPagination: QueryBuilder[T, PostgresDialect, PostgresEscape] = {
    new PostgresQueryBuilder[T](parameters.copy(pagination = None))
  }
}