Dynamic table name override in Slick table - scala

I have defined a slick table as below on DB view. Every day we create a dated view matching the same structure with name appended with date as T_SUMMARY_ i.e.T_SUMMARY_20131213.
Is there a way in slick where table name can be dynamically overridden to generate required query for a correct dated view.
object TSummary extends Table[(String)]("T_SUMMARY")
{
def id = column[String]("ROWID", O.PrimaryKey)
def tNum = column[Int]("T_NUM")
def tName = column[Int]("T_NAME")
def * = id
}

In Slick 1.0.1:
def mkSummaryTable(name: String) = new Table[(String)](name){
def id = column[String]("ROWID", O.PrimaryKey)
def tNum = column[Int]("T_NUM")
def tName = column[Int]("T_NAME")
def * = id
}
val current = mkSummaryTable("T_SUMMARY_20131213")
for( r <- Query(current) ) yield r.tName
For Slick 2.0 see https://groups.google.com/d/msg/scalaquery/95Z7AfxKP_4/omGnAtuN8FcJ:
class MyTable(tag: Tag, tableName: String) extends Table[(String)](tag, tableName){
def id = column[String]("ROWID", O.PrimaryKey)
def tNum = column[Int]("T_NUM")
def tName = column[Int]("T_NAME")
def * = id
}
val tQ = TableQuery[MyTable]((tag:Tag) => new MyTable(tag, "SomeTableName")) filter ...

Related

How to parameterize table name in Slick

class MyTable(tag: Tag) extends Table[MyEntity](tag, "1970Table") {
def id = column[Int]("id")
override def * =
(
id
) <> (MyEntity.tupled, MyEntity.unapply)
}
val myTable = TableQuery[MyTable]
class MyRepository(val config: DatabaseConfig[JdbcProfile])
extends MyRepository[MyTable, String] {
override val table: config.profile.api.TableQuery[MyTable] = myTable
def insert(me: MyEntity): Future[Int] = {
db.run(table += me)
}
}
I use this in my other classes like this:
val myRepository = new MyRepository(dbConfig)
myRepository.insert(myrecord)
Question
I would like to not have a hardcoded tablename but rather make the tablename dynamic.
I would like to change the insert method such that it accepts a year (int) parameter and based on the year parameter it chooses the right table. i.e. if the year passed in is 1970 then table name is 1970Table but if the year passed in is 1980 then the table is 1980Table.
Try
class MyRepository(val config: DatabaseConfig[JdbcProfile]) {
import config._
import profile.api._
abstract class MyTable(tag: Tag, name: String) extends Table[MyEntity](tag, name) {
def id = column[Int]("id")
override def * = (id) <> (MyEntity.tupled, MyEntity.unapply)
}
class Table1970(tag: Tag) extends MyTable[MyEntity](tag, "1970Table")
class Table1980(tag: Tag) extends MyTable[MyEntity](tag, "1980Table")
val table1970 = TableQuery[Table1970]
val table1980 = TableQuery[Table1980]
def insert(me: MyEntity, year: Int): Future[Int] = db.run {
year match {
case "1970" => table1970 += me
case "1980" => table1980 += me
}
}
}
Now
val myRepository = new MyRepository(dbConfig)
myRepository.insert(myrecord, "1970")
There is two apply methods in TableQuery. val myTable = TableQuery[MyTable] -
this one uses macros to create MyTable.
The other one is defined like this:
def apply[E <: AbstractTable[_]](cons: Tag => E): TableQuery[E] =
new TableQuery[E](cons)
So you can do smth like this
class MyTable(tag: Tag, tableName: String) extends Table[MyEntity](tag, tableName)
...
def myTable(name: String) = TableQuery[MyTable](tag => new MyTable(tag, name))
Now you can predefine all tables you need and use them or do smth like this
class MyRepository(val config: DatabaseConfig[JdbcProfile])
extends MyRepository[MyTable, String] {
override def table(year: Int): config.profile.api.TableQuery[MyTable] = myTable(year.toString)
def insert(me: MyEntity, year: Int): Future[Int] = {
db.run(table(year) += me)
}
}

Slick select all rows for table with no filtering

How can I get a collection of JurisdictionRow objects? I need a SELECT * FROM jurisdiction
object JurisdictionRepo extends {
val profile = slick.driver.MySQLDriver
} with JurisdictionRepo
trait JurisdictionRepo {
private val dbConfig: DatabaseConfig[MySQLDriver] = DatabaseConfig.forConfig("pnga-master-data")
private val db = dbConfig.db
val profile: slick.driver.JdbcProfile
val tableName = "jurisdiction"
def add(jurisdictionRow: JurisdictionRow): Future[Unit] = db.run(query += jurisdictionRow).map { _ => () }
def delete(id: String): Future[Int] = db.run(query.filter(_.id === id).delete)
def get(id: String): Future[Option[JurisdictionRow]] = db.run(query.filter(_.id === id).result.headOption)
def all() = ???
import profile.api._
lazy val schema: profile.SchemaDescription = query.schema
case class JurisdictionRow(id: String,
parentId: String,
name: String,
code: String)
class Jurisdiction(_tableTag: Tag) extends Table[JurisdictionRow](_tableTag, tableName) {
val id: Rep[String] = column[String](s"${tableName}_id", O.PrimaryKey, O.Length(36, varying=true))
val parentId: Rep[String] = column[String]("parent_id", O.Length(36, varying=true))
val name: Rep[String] = column[String]("name", O.Length(255, varying=true))
val code: Rep[String] = column[String]("code", O.Length(255, varying=true))
def * = (id, parentId, name, code) <> (JurisdictionRow.tupled, JurisdictionRow.unapply _)
}
lazy val query = new TableQuery(tag => new Jurisdiction(tag))
}
I would like to implement the all method to return all possible JurisdictionRow objects in the table. This seems like a common case, but the Slick documentation has not been helpful. I just need a plain old result set, no fancy filtering, etc.
Just replicate what you already have in the other queries but without the filter part.
def all = db.run(query.result)
Have look at the first example:
http://slick.lightbend.com/doc/3.2.0/gettingstarted.html#querying

Slick inSetBind or inSet doesn't work

I'm trying to limit the results of a Slick 3.1.0 query using inSetBind and always get an empty set back.
Here is the setup:
case class VTag(tagID: Option[Long], kind: String, name: String) {
def toUITag = UITag(tagID = tagID.get, kind = kind, name = name)
}
class VTags(tag: Tag) extends Table[VTag](tag, TagsDao.tableName) {
def tagID = column[Long]("ID", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def kind = column[String]("kind")
def * = (tagID.?, name, kind) <>((VTag.apply _).tupled, VTag.unapply)
}
object TagsDao extends SurgeonsTableObject {
val tableVTags = TableQuery[VTags]
val db = GlobalDAO.db
override def tableName: String = "VTAGS"
override def tableSchema: H2Driver.DDL = tableVTags.schema
def getTagsByName(tagsToSearch: Set[String]): Future[Seq[VTag]] = {
val tagList: List[String] = tagsToSearch.toList
val q = for (c <- tableVTags if c.name.inSetBind(tagList)) yield c
db.run(q.result)
}
def all: Future[Seq[VTag]] = {
val q = for (c <- tableVTags.sortBy(_.tagID.asc)) yield c
db.run(q.result)
}
}
getTagsByName is the method that creates problem. All return all 100 tags I insert there. getTagsByName return always zero. I've tried using inSet / inSetBind, passing as input a list(tagList) or a set (tagsToSearch). Always empty result set. What's going on.
Please don't tell me I have to write SQL ...

Scala Slick 2.0: converting from Query[Mixed, T#TableElementType] to Query[T, T#TableElementType]

Assume we have a table
class Entry(tag :Tag) extends Table[(String, Long)](tag, "entries") {
def name = column[String]("name")
def value = column[Long]("value")
def * = (name, value)
}
val Entries = new TableQuery(new Entry(_))
and a query of type Query[(Column[String], Column[Long]), (String, Long)]. Can I somehow convert it to Query[Entry, (String, Long)]? This would be very useful in case of grouping queries such as Entries.groupBy(_.name).map(g=>(g._1, g._2.map(_.value).avg))
try this :
case class Entry(name: String,value: Long)
class Entries(tag :Tag) extends Table[Entry](tag, "entries") {
def name = column[String]("name")
def value = column[Long]("value")
def * = (name, value) <>(Entry.tupled, Entry.unapply )
}
val Entries = TableQuery[Entries]

How to create a class instance from slick query?

I am finding it difficult to figure out the best wy to create an instance of a class (a DTO class) which can be passed as json to the calling client.
I have the following class structure.
object Suppliers extends Table[(Int, String, String, String, String, String)]("SUPPLIERS") {
def id = column[Int]("SUP_ID", O.PrimaryKey) // This is the primary key column
def name = column[String]("SUP_NAME")
def street = column[String]("STREET")
def city = column[String]("CITY")
def state = column[String]("STATE")
def zip = column[String]("ZIP")
def * = id ~ name ~ street ~ city ~ state ~ zip
}
object Coffees extends Table[(Int,String, Double,Int, Int)]("COFFEES") {
def id = column[Int]("Id",O.PrimaryKey)
def name = column[String]("COF_NAME")
def price = column[Double]("PRICE")
def sales = column[Int]("SALES")
def total = column[Int]("TOTAL")
def * = id ~ name ~ price ~ sales ~ total
}
object CoffeeSuppliers extends Table[(Int,Int,Int)]("CoffeeSuppliers") {
def id = column[Int]("Id",O.PrimaryKey)
def supID = column[Int]("Sup_ID")
def coffeeID = column[Int]("Coffee_ID")
def supplier = foreignKey("SUP_FK", supID, Suppliers)(_.id)
def coffees = foreignKey("COF_FK", coffeeID,Coffees)(_.id)
def * = id ~ supID ~ coffeeID
}
I am using this simple join query to retrieve Supplier with id 101 and all the coffees he supplies.
val q3 = for {
((cs,c),s) <- CoffeeSuppliers innerJoin
Coffees on (_.coffeeID === _.id) innerJoin
Suppliers on (_._1.supID === _.id) if cs.supID === 101
} yield (cs,c,s)
The query is working fine and I am able to retrieve the data.
But, I want to construct a DTO class out of the query result. The Class structure is as fallows
case class CoffeeDTO(
id:Option[Int] = Some(0),
name:String[String] = "",
price:Double= 0.0
)
case class SupplierDTO (
id:Option[Int] = Some(0),
name:String = "",
coffees:List[CoffeeDTO] = Nil
)
How to create an instance of SupplierDTO and assign the values from the query result?
How about something like this:
q3.map{ case (cs,c,s) => ((s.id.?,s.name),(c.id.?,c.name,c.price)) } // remove not needed columns and make ids Options
.list // run query
.groupBy( _._1 ) // group by supplier
.map{ case (s,scPairs) => SupplierDTO( s._1, // map each group to a supplier with associated coffees
s._2,
scPairs.map(_._2) // map group of pairs to only coffee tuples
.map(CoffeeDTP.tupled) // create coffee objects
)}
.head // take just the one supplier out of the list