Skip to content

Instantly share code, notes, and snippets.

@kgcrom
Last active July 30, 2016 14:30
Show Gist options
  • Save kgcrom/75012163bb899e0e5c8ae4e889096ed7 to your computer and use it in GitHub Desktop.
Save kgcrom/75012163bb899e0e5c8ae4e889096ed7 to your computer and use it in GitHub Desktop.
Play + Slick 이렇게 하는거 맞나요?
{
"total": 2824,
"page": 0,
"offset": 0,
"size": 50,
"data": [
{
"id": 1234,
"ownerId": 4567,
"name": "Kang",
"status": "active",
"created": 1469717228517,
"updated": 1469756483542,
"ownerName": "Han gu "
}
....
]
}
object SearchApp extends Controller {
def teamList(page: Int, size: Int) = Action.async { request =>
val q = request.getQueryString("q") match {
case k: Option[String] => k
case _ => None
}
val sort = request.queryString.get("sort") match {
case Some(s) => SortBy.parse(s(0))
case _ => ("id", Desc)
}
val filterConditions = FilterCondition.parseQuery(request.getQueryString("fq").getOrElse(null))
val filterType = request.getQueryString("ft").getOrElse("and")
teamDao.list(page, size, q, sort, filterConditions, filterType).map(t => {
val json: JsValue = Json.obj(
"total" -> t.total,
"page" -> t.page,
"offset" -> t.offset,
"size" -> t.size,
"data" -> t.items.map(k => {
TeamsSearchResultRow(k._1, k._2, k._3, k._4, k._5, k._6, k._7)
})
)
Ok(json)
})
}
}
trait Tables {
...
/** Entity class storing rows of table Teams
*
* @param id Database column id SqlType(int4), PrimaryKey
* @param ownerId Database column owner_id SqlType(int4)
* @param name Database column name SqlType(varchar), Length(50,true)
* @param status Database column status SqlType(varchar), Length(15,true)
* @param created Database column created SqlType(timestamptz)
* @param updated Database column updated SqlType(timestamptz) */
case class TeamsRow(id: Int, ownerId: Int, name: String, status: String, created: java.sql.Timestamp, updated: Option[java.sql.Timestamp])
/** GetResult implicit for fetching TeamsRow objects using plain SQL queries */
implicit def GetResultTeamsRow(implicit e0: GR[Int], e1: GR[String], e2: GR[java.sql.Timestamp]): GR[TeamsRow] = GR {
prs => import prs._
TeamsRow.tupled((<<[Int], <<[Int], <<[String], <<[String], <<[java.sql.Timestamp], <<?[java.sql.Timestamp]))
}
/** Table description of table teams. Objects of this class serve as prototypes for rows in queries. */
class Teams(_tableTag: Tag) extends Table[TeamsRow](_tableTag, "teams") {
def * = (id, ownerId, name, status, created, updated) <>(TeamsRow.tupled, TeamsRow.unapply)
/** Maps whole row to an option. Useful for outer joins. */
def ? = (Rep.Some(id),Rep.Some(ownerId), Rep.Some(name), Rep.Some(status), Rep.Some(created), updated).shaped.<>({ r => import r._; _1.map(_ => TeamsRow.tupled((_1.get, _2.get, _3.get, _4.get, _5.get, _6))) }, (_: Any) => throw new Exception("Inserting into ? projection not supported."))
/** Database column id SqlType(int4), PrimaryKey */
val id: Rep[Int] = column[Int]("id", O.PrimaryKey)
/** Database column owner_id SqlType(int4) */
val ownerId: Rep[Int] = column[Int]("owner_id")
/** Database column name SqlType(varchar), Length(50,true) */
val name: Rep[String] = column[String]("name", O.Length(50, varying = true))
/** Database column status SqlType(varchar), Length(15,true) */
val status: Rep[String] = column[String]("status", O.Length(15, varying = true))
/** Database column created SqlType(timestamptz) */
val created: Rep[java.sql.Timestamp] = column[java.sql.Timestamp]("created")
/** Database column updated SqlType(timestamptz) */
val updated: Rep[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("updated")
}
/** Collection-like TableQuery object for table Teams */
lazy val Teams = new TableQuery(tag => new Teams(tag))
/** Entity class storing rows of table Members
*
* @param id Database column id SqlType(int4), PrimaryKey
* @param teamId Database column team_id SqlType(int4), Default(None)
* @param accountId Database column account_id SqlType(varchar), Length(50,true), Default(None)
* @param name Database column name SqlType(varchar), Length(255,true)
* @param email Database column email SqlType(varchar), Length(255,true)
* @param authority Database column authority SqlType(varchar), Length(50,true)
* @param status Database column status SqlType(varchar), Length(50,true)
* @param type Database column status SqlType(varchar), Length(50,true)
* @param created Database column created SqlType(int8), Default(None)
* @param updated Database column updated SqlType(int8), Default(None) */
case class MembersRow(id: Int, teamId: Int, accountId: Option[String], name: String, email: String, authority: Option[String], status: String, `type`: String, created: Option[java.sql.Timestamp], updated: Option[java.sql.Timestamp])
/** GetResult implicit for fetching MembersRow objects using plain SQL queries */
implicit def GetResultMembersRow(e0: GR[Int], e1: GR[Int], e2: GR[String], e3: GR[String], e4: GR[java.sql.Timestamp]): GR[MembersRow] = GR {
prs => import prs._
MembersRow.tupled((<<[Int], <<[Int], <<?[String], <<[String], <<[String], <<?[String], <<[String], <<[String], <<?[java.sql.Timestamp], <<?[java.sql.Timestamp]))
}
/** Table description of table members. Objects of this class serve as prototypes for rows in queries. */
class Members(_tableTag: Tag) extends Table[MembersRow](_tableTag, "members") {
def * = (id, teamId, accountId, name, email, authority, status, `type`, created, updated) <>(MembersRow.tupled, MembersRow.unapply)
/** Maps whole row to an option. Useful for outer joins. */
def ? = (Rep.Some(id), Rep.Some(teamId), accountId, Rep.Some(name), Rep.Some(email), authority, Rep.Some(status), `type`, created, updated).shaped.<>({ r => import r._; _1.map(_ => MembersRow.tupled((_1.get, _2.get, _3, _4.get, _5.get, _6, _7.get, _8, _9, _10))) }, (_: Any) => throw new Exception("Inserting into ? projection not supported."))
/** Database column id SqlType(int4), PrimaryKey */
val id: Rep[Int] = column[Int]("id", O.PrimaryKey)
/** Database column team_id SqlType(int4), Default(None) */
val teamId: Rep[Int] = column[Int]("team_id")
/** Database column account_id SqlType(varchar), Length(50,true), Default(None) */
val accountId: Rep[Option[String]] = column[Option[String]]("account_id", O.Length(50, varying = true))
/** Database column name SqlType(varchar), Length(255,true) */
val name: Rep[String] = column[String]("name", O.Length(255, varying = true))
/** Database column email SqlType(varchar), Length(255,true) */
val email: Rep[String] = column[String]("email", O.Length(255, varying = true))
/** Database column authority SqlType(varchar), Length(50,true) */
val authority: Rep[Option[String]] = column[Option[String]]("authority", O.Length(50, varying = true))
/** Database column status SqlType(varchar), Length(50,true) */
val status: Rep[String] = column[String]("status", O.Length(50, varying = true))
/** Database column type SqlType(varchar), Length(50,true) */
val `type`: Rep[String] = column[String]("type", O.Length(50, varying = true))
/** Database column created SqlType(int8), Default(None) */
val created: Rep[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("created")
/** Database column updated SqlType(int8), Default(None) */
val updated: Rep[Option[java.sql.Timestamp]] = column[Option[java.sql.Timestamp]]("updated")
}
/** Collection-like TableQuery object for table Members */
lazy val Members = new TableQuery(tag => new Members(tag))
...
}
class TeamsDAO extends HasDatabaseConfig[JdbcProfile] {
private val teams: TableQuery[Teams] = TableQuery[Teams]
private val members: TableQuery[Members] = TableQuery[Members]
def list(page: Int, size: Int,
q: Option[String], sortColumn: (String, SortDirection),
filterConditions: Array[FilterCondition], filterType: String): Future[JoinPage[Seq[(Int, Int, String, String, java.sql.Timestamp, Option[java.sql.Timestamp], String)]]] = {
val offset = if (page < 0) 0 else (page * size)
var query = teams.filter { team => {
val collection = extractCondition(filterConditions, Some(q), team)
.collect({ case Some(criteria) => criteria })
if (filterType == "or") {
collection.reduceLeftOption(_ || _).getOrElse(true: Rep[Boolean])
} else {
collection.reduceLeftOption(_ && _).getOrElse(true: Rep[Boolean])
}
}
}
//TODO warning 관련 refactoring
val (sortField, sortDirection) = sortColumn
query = (
for {
team <- query.filter(t => {
q.isDefined match {
case true => {
q.get.forall(_.isDigit) match {
case true => (t.name.toLowerCase like "%" + q.get.toLowerCase + "%") || (t.domain.toLowerCase like "%" + q.get.toLowerCase + "%") || (t.id === q.get.toInt)
case false => {
val l = q.get.toLowerCase
(t.name.toLowerCase like "%" + l + "%") || (t.domain.toLowerCase like "%" + l + "%")
}
}
}
case false => true: Rep[Boolean]
}
}).sortBy(sortField match {
case "id" => if (sortDirection == Desc) _.id.desc else _.id.asc
case "ownerId" => if (sortDirection == Desc) _.ownerId.desc else _.ownerId.asc
case "name" => if (sortDirection == Desc) _.name.desc else _.name.asc
case "status" => if (sortDirection == Desc) _.status.desc else _.status.asc
case "created" => if (sortDirection == Desc) _.created.desc else _.created.asc
case _ => _.id.desc
})
} yield (team))
val joinQuery = for {
t <- query
m <- members if t.ownerId === m.id
} yield (t.id, t.ownerId, t.name, t.status, t.created, t.updated, m.name)
for {
totalRows <- dbConfig.db.run(joinQuery.size.result)
result <- dbConfig.db.run(joinQuery.drop(offset).take(size).result)
} yield (JoinPage(result, page, offset, size, totalRows))
}
}
object TeamsDAO {
import play.api.libs.functional.syntax._
import slick.jdbc.{GetResult => GR}
implicit val teamsListWrites: Writes[TeamsSearchResultRow] = (
(JsPath \ "id").write[Int] and
(JsPath \ "ownerId").write[Int] and
(JsPath \ "name").write[String] and
(JsPath \ "status").write[String] and
(JsPath \ "created").write[java.sql.Timestamp] and
(JsPath \ "updated").write[Option[java.sql.Timestamp]] and
(JsPath \ "ownerName").write[String]
) (unlift(TeamsSearchResultRow.unapply))
case class TeamsSearchResultRow(id: Int, ownerId: Int, name: String,
status: String, created: java.sql.Timestamp,
updated: Option[java.sql.Timestamp], ownerName: String)
}
@kgcrom
Copy link
Author

kgcrom commented Jul 30, 2016

현재 프로젝트에서 필요한 부분만 추려냄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment