Last active
July 30, 2016 14:30
-
-
Save kgcrom/75012163bb899e0e5c8ae4e889096ed7 to your computer and use it in GitHub Desktop.
Play + Slick 이렇게 하는거 맞나요?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"total": 2824, | |
"page": 0, | |
"offset": 0, | |
"size": 50, | |
"data": [ | |
{ | |
"id": 1234, | |
"ownerId": 4567, | |
"name": "Kang", | |
"status": "active", | |
"created": 1469717228517, | |
"updated": 1469756483542, | |
"ownerName": "Han gu " | |
} | |
.... | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | |
... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
현재 프로젝트에서 필요한 부분만 추려냄