Skip to content

Commit ade02b0

Browse files
authored
add pagination and order support to /datasets query (#32)
1 parent df3a847 commit ade02b0

File tree

5 files changed

+79
-11
lines changed

5 files changed

+79
-11
lines changed

acdc-core/src/main/scala/com/salesforce/mce/acdc/db/DatasetQuery.scala

+24-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import slick.jdbc.PostgresProfile.api._
1515

1616
object DatasetQuery {
1717

18+
object OrderColumn extends Enumeration {
19+
20+
val CreatedAt = Value("created_at")
21+
val UpdatedAt = Value("updated_at")
22+
}
23+
1824
def now() = LocalDateTime.now()
1925

2026
case class ForName(name: String) {
@@ -62,7 +68,23 @@ object DatasetQuery {
6268

6369
}
6470

65-
def filter(like: String): DBIO[Seq[DatasetTable.R]] =
66-
DatasetTable().filter(_.name.like(s"$like")).result
71+
def filter(
72+
like: String,
73+
order: OrderColumn.Value,
74+
limit: Int,
75+
offset: Int
76+
): DBIO[Seq[DatasetTable.R]] = {
77+
val ordering = order match {
78+
case OrderColumn.CreatedAt => t: DatasetTable => t.createdAt
79+
case OrderColumn.UpdatedAt => t: DatasetTable => t.updatedAt
80+
case _ => throw new MatchError("unexpected order")
81+
}
82+
DatasetTable()
83+
.filter(_.name.like(s"$like"))
84+
.sortBy(ordering(_).desc)
85+
.drop(offset)
86+
.take(limit)
87+
.result
88+
}
6789

6890
}

acdc-ws/app/Module.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
import com.google.inject.AbstractModule
99

10-
import utils.{Authorization, AuthorizationSettings}
1110
import tasks.AuthSettingReloadTask
11+
import utils.{Authorization, AuthorizationSettings}
1212

1313
class Module extends AbstractModule {
1414

acdc-ws/app/controllers/DatasetController.scala

+45-6
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import com.salesforce.mce.acdc.db.DatasetQuery
1919
import com.salesforce.mce.acdc.db.DatasetTable
2020
import models.CreateDatasetRequest
2121
import models.DatasetResponse
22+
import play.api.libs.json.JsString
2223
import services.DatabaseService
2324
import utils.{AuthTransformAction, InvalidApiRequest, ValidApiRequest}
24-
import play.api.libs.json.JsString
2525

2626
@Singleton
2727
class DatasetController @Inject() (
@@ -90,11 +90,50 @@ class DatasetController @Inject() (
9090
case InvalidApiRequest(_) => Future.successful(Unauthorized(JsNull))
9191
}
9292

93-
def filter(like: String) = authAction.async {
94-
case ValidApiRequest(apiRole, _) =>
95-
db.async(DatasetQuery.filter(like)).map(rs => Ok(Json.toJson(rs.map(toResponse))))
96-
case InvalidApiRequest(_) =>
97-
Future.successful(Unauthorized(JsNull))
93+
def filter(like: String, order: Option[String], page: Option[Int], perPage: Option[Int]) =
94+
authAction.async {
95+
case ValidApiRequest(apiRole, _) =>
96+
val validated = for {
97+
vOrder <- DatasetController.validateOrder(order)
98+
vPage <- DatasetController.validateOne(page.getOrElse(1), "page")
99+
limit <- DatasetController.validateOne(perPage.getOrElse(50), "per_page")
100+
} yield (vOrder, limit, (vPage - 1) * limit)
101+
102+
validated match {
103+
case Right((o, limit, offset)) =>
104+
db.async(DatasetQuery.filter(like, o, limit, offset))
105+
.map(rs => Ok(Json.toJson(rs.map(toResponse))))
106+
case Left(msg) =>
107+
Future.successful(BadRequest(JsString(msg)))
108+
}
109+
110+
case InvalidApiRequest(_) =>
111+
Future.successful(Unauthorized(JsNull))
112+
}
113+
114+
}
115+
116+
object DatasetController {
117+
118+
private def validateOrder(
119+
order: Option[String]
120+
): Either[String, DatasetQuery.OrderColumn.Value] = {
121+
order
122+
.fold[Either[String, DatasetQuery.OrderColumn.Value]](
123+
Right(DatasetQuery.OrderColumn.CreatedAt)
124+
) { o =>
125+
try {
126+
Right(DatasetQuery.OrderColumn.withName(o))
127+
} catch {
128+
case e: NoSuchElementException =>
129+
Left(s"Unknow order $o")
130+
}
131+
}
132+
}
133+
134+
private def validateOne(num: Int, name: String): Either[String, Int] = {
135+
if (num < 1) Left(s"$name must be at least 1")
136+
else Right(num)
98137
}
99138

100139
}

acdc-ws/app/routers/ApiRouter.scala

+8-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ class ApiRouter @Inject() (
2424
case POST(p"/dataset") => dataset.create()
2525
case PUT(p"/dataset/$name") => dataset.update(name)
2626
case GET(p"/dataset/$name") => dataset.get(name)
27-
case GET(p"/datasets" ? q"like=$like") => dataset.filter(like)
27+
case GET(
28+
p"/datasets" ?
29+
q"like=$like" &
30+
q_o"order=$order" &
31+
q_o"page=${int(page)}" &
32+
q_o"per_page=${int(perPage)}"
33+
) =>
34+
dataset.filter(like, order, page, perPage)
2835
case DELETE(p"/dataset/$name") => dataset.delete(name)
2936

3037
case POST(p"/instance") => instance.create()

version.sbt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ThisBuild / version := "0.6.2"
1+
ThisBuild / version := "0.6.3"

0 commit comments

Comments
 (0)