1 /*
2  *  Make.org Core API
3  *  Copyright (C) 2021 Make.org
4  *
5  * This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  *
18  */
19 
20 package org.make.api.demographics
21 
22 import org.make.api.extensions.MakeDBExecutionContextComponent
23 import org.make.api.technical.DatabaseTransactions._
24 import org.make.api.technical.PersistentServiceUtils._
25 import org.make.api.technical.ScalikeSupport._
26 import org.make.api.technical.{PersistentCompanion, ShortenedNames}
27 import org.make.core.Order
28 import org.make.core.demographics.{DemographicsCard, DemographicsCardId, LabelsValue}
29 import org.make.core.question.QuestionId
30 import org.make.core.reference.Language
31 import org.make.core.technical.Pagination
32 
33 import cats.data.NonEmptyList
34 import cats.implicits._
35 import scalikejdbc._
36 
37 import scala.concurrent.Future
38 
39 trait DefaultPersistentDemographicsCardServiceComponent extends PersistentDemographicsCardServiceComponent {
40   self: MakeDBExecutionContextComponent =>
41 
42   implicit val labelsBinder: Binders[NonEmptyList[LabelsValue]] = jsonNelBinder[LabelsValue]
43 
44   val CountColumnName = "count"
45 
46   override lazy val persistentDemographicsCardService: PersistentDemographicsCardService =
47     new PersistentDemographicsCardService with ShortenedNames {
48 
49       private val demographicsCards = SQLSyntaxSupportFactory[DemographicsCard]()
50       private val dc = demographicsCards.syntax
51 
52       private implicit val companion: PersistentCompanion[DemographicsCard, DemographicsCard] =
53         new PersistentCompanion[DemographicsCard, DemographicsCard] {
54           override val alias: SyntaxProvider[DemographicsCard] = dc
55           override val defaultSortColumns: NonEmptyList[SQLSyntax] = NonEmptyList.of(alias.name)
56           override val columnNames: Seq[String] =
57             Seq("name", "question_id", "layout", "dataType", "languages", "titles", "createdAt", "updatedAt")
58         }
59 
60       override def get(id: DemographicsCardId): Future[Option[DemographicsCard]] = {
61         implicit val context: EC = readExecutionContext
62         Future(NamedDB("READ").retryableTx { implicit session =>
63           withSQL {
64             select.from(demographicsCards.as(dc)).where.eq(dc.id, id)
65           }.map(demographicsCards.apply(dc.resultName))
66             .single()
67         })
68       }
69 
70       override def list(
71         offset: Option[Pagination.Offset],
72         end: Option[Pagination.End],
73         sort: Option[String],
74         order: Option[Order],
75         languages: Option[List[Language]],
76         dataType: Option[String],
77         questionId: Option[QuestionId]
78       ): Future[Seq[DemographicsCard]] = {
79         implicit val context: EC = readExecutionContext
80         Future(NamedDB("READ").retryableTx { implicit session =>
81           withSQL {
82             sortOrderQuery(
83               offset.orZero,
84               end,
85               sort,
86               order,
87               select
88                 .from(demographicsCards.as(dc))
89                 .where(
90                   sqls.toAndConditionOpt(
91                     languages.map(l => sqls"${dc.languages} @> ARRAY[${l.map(_.value)}]"),
92                     dataType.map(sqls.like(dc.dataType, _)),
93                     questionId.map(sqls.eq(dc.questionId, _))
94                   )
95                 )
96             )
97           }.map(demographicsCards.apply(dc.resultName))
98             .list()
99         })
100       }
101 
102       override def persist(demographicsCard: DemographicsCard): Future[DemographicsCard] = {
103         implicit val context: EC = writeExecutionContext
104         Future(NamedDB("WRITE").retryableTx { implicit session =>
105           withSQL {
106             insert.into(demographicsCards).namedValues(autoNamedValues(demographicsCard, demographicsCards.column))
107           }.update()
108         }).as(demographicsCard)
109       }
110 
111       override def modify(demographicsCard: DemographicsCard): Future[DemographicsCard] = {
112         implicit val context: EC = writeExecutionContext
113         Future(NamedDB("WRITE").retryableTx { implicit session =>
114           withSQL {
115             update(demographicsCards)
116               .set(autoNamedValues(demographicsCard, demographicsCards.column, "id", "createdAt"))
117               .where
118               .eq(dc.id, demographicsCard.id)
119           }.update()
120         }).as(demographicsCard)
121       }
122 
123       override def count(
124         languages: Option[List[Language]],
125         dataType: Option[String],
126         questionId: Option[QuestionId]
127       ): Future[Int] = {
128         implicit val context: EC = readExecutionContext
129         Future(NamedDB("READ").retryableTx { implicit session =>
130           withSQL {
131             select(sqls.count)
132               .from(demographicsCards.as(dc))
133               .where(
134                 sqls.toAndConditionOpt(
135                   languages.map(l => sqls"${dc.languages} @> ARRAY[${l.map(_.value).mkString(",")}]"),
136                   dataType.map(sqls.like(dc.dataType, _)),
137                   questionId.map(sqls.eq(dc.questionId, _))
138                 )
139               )
140           }.map(_.int(CountColumnName)).single().getOrElse(0)
141         })
142       }
143 
144       override def delete(id: DemographicsCardId): Future[Unit] = {
145         implicit val context: EC = writeExecutionContext
146         Future(NamedDB("WRITE").retryableTx { implicit session =>
147           withSQL {
148             deleteFrom(demographicsCards.as(dc)).where.eq(dc.id, id)
149           }.execute()
150         }).void
151       }
152 
153     }
154 }
Line Stmt Id Pos Tree Symbol Tests Code
42 20829 1630 - 1656 ApplyToImplicitArgs org.make.api.technical.ScalikeSupport.jsonNelBinder org.make.api.technical.ScalikeSupport.jsonNelBinder[org.make.core.demographics.LabelsValue](demographics.this.LabelsValue.codec, demographics.this.LabelsValue.codec)
42 19622 1643 - 1643 Select org.make.core.demographics.LabelsValue.codec demographics.this.LabelsValue.codec
42 21727 1643 - 1643 Select org.make.core.demographics.LabelsValue.codec demographics.this.LabelsValue.codec
44 19829 1682 - 1689 Literal <nosymbol> "count"