Slick inSetBind or inSet doesn't work - scala

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 ...

Related

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 join two tables and get result of both

I have a Many to Many relationship setup like this:
Person <-> PersonField <-> Field
Now I want to query not only all the fields of a Person (I can do that), but a joined version of PersonField with Field of a Person. (I want to query/retrieve the Information in the Pivot/Intermediate Table "PersonField" as well!)
Person:
case class Person(id: Long, name: String)
{
def fields =
{
person <- Persons.all.filter(_.id === this.id)
field <- person.fields
} yield field
}
class Persons(tag: Tag) extends Table[Person](tag, "persons")
{
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def * = (id, name) <> (Person.tupled, Person.unapply)
def fields = PersonFields.all.filter(_.personID === id).flatMap(_.fieldFK)
}
object Persons
{
lazy val all = TableQuery[Persons]
}
Field:
case class Field(id: Long, name: String, description: Option[String])
class Fields(tag: Tag) extends Table[Field](tag, "fields")
{
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def description = column[Option[String]]("description")
def * = (id, name, description) <> (Field.tupled, Field.unapply)
}
object Fields
{
lazy val all = TableQuery[Fields]
}
PersonField:
case class PersonField(id: Long, personID: Long, fieldID: Long, value: String)
// TODO add constraint to make (personID, fieldID) unique
class PersonFields(tag: Tag) extends Table[PersonField](tag, "person_field")
{
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def personID = column[Long]("person_id")
def fieldID = column[Long]("field_id")
def value = column[String]("value")
def * = (id, personID, fieldID, value) <> (PersonField.tupled, PersonField.unapply)
def personFK = foreignKey("person_fk", personID, Persons.all)(_.id)
def fieldFK = foreignKey("field_fk", fieldID, Fields.all)(_.id)
}
object PersonFields
{
lazy val all = TableQuery[PersonFields]
}
Now to query all the fields of a Person I have a little helper-class:
def getFields(p: Person): Future[Seq[Field]] =
{
val query = p.fields
db.run(query.result)
}
So I can do
val personX ...
personX.onSuccess
{
case p: Person =>
{
val fields = helper.getFields(p)
fields.onSuccess
{
case f: Seq[Field] => f foreach println
}
}
}
Now each field of personX gets printed to the console. Works like a charm.
The thing is, I want to get the PersonField as well (with the Field)!
So I tried the following changes (among others that didn't work, which I can't remember)
In Person:
def fields =
{
for
{
person <- Persons.all.filter(_.id === this.id)
field <- person.fields join Fields.all on (_.fieldID === _.id)
} yield field
}
In PersonS
def fields = PersonFields.all.filter(_.personID === id) // No flatMap here!
then getFields(p: Person) looks like this:
def getFields(p: Person): Future[Seq[(PersonField, Field)]]
but
personX.onSuccess
{
case p: Person =>
{
val fields = helper.getFields(p)
fields.onSuccess
{
case f: Seq[(PersonField, Field)] => f map(f => println(f._1)}
}
}
}
gives me nothing, so I guess my join must be wrong. But what exactly am I doing wrong?
You can join all three, then yield the result
for {
((personField, person), field) <- PersonFields.all join Persons.all on (_.personId === _.id) join Fields.all on (_._1.fieldId === _.id)
if person.id === this.id
} yield (personField, person, field)
(I am not sure I got exactly what you were trying to get out of the query, so you can just edit the yield part )

How can compare column[option[DateTime] with DateTime.now on a filter of slick 3.0

i have the next problem..
im using spray.http.DateTime, and my mapper is:
implicit val JavaUtilDateTimeMapper =
MappedColumnType.base[DateTime, Timestamp] (
d => new Timestamp(d.clicks),
d => spray.http.DateTime(d.getTime))
case class EventosModelTable(
id: Option[Long],
idCliente: Option[Long],
idPlan: Option[Long] = None,
idServicio: Option[Long] = None,
tipo: TipoEventos.Value,
fechaInicio: DateTime,
fechaFin: Option[DateTime]
) extends BaseModel
class EventosTabla(tag: Tag) extends Table[EventosModelTable](tag, "eventos") with BaseTabla{
override def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def idCliente = column[Long]("id_cliente")
def idPlan = column[Option[Long]]("id_plan")
def idServicio = column[Option[Long]]("id_servicio")
def tipo = column[TipoEventos.Value]("tipo_evento")
def fechaInicio = column[DateTime]("fecha_inicio")
def fechaFin = column[Option[DateTime]]("fecha_fin")
def * = (id.?,idCliente.?,idPlan,idServicio,tipo,fechaInicio,fechaFin) <> (EventosModelTable.tupled, EventosModelTable.unapply _)
def cliente = foreignKey("cliente",idCliente,TableQuery[ClientesTabla])(_.id)
def plan = foreignKey("plan",idPlan,TableQuery[PlanesTabla])(_.id)
}
then.. i need find Event's where fechaFin are Null or fechaFin> DateTime.now...
but the problem is that fechaFin can be Null then is a Option value, and i cant compare with a DateTime.now.. the compile error is that Some[DateTime] dont have > method.
I will appreciate any help
the query is as follows..
def getAltasBajas(id : Long) : DBIOAction[Seq[EventosModelTable],NoStream,Effect.All] = {
val q = for {
altasBajas <- tabla.filter(_.idCliente === id)
if altasBajas.fechaFin.isEmpty || (altasBajas.fechaFin.isDefined && (altasBajas.fechaFin)<(DateTime.now))
}yield altasBajas
q.result
}
I found this answer that would indicate that your implementation should work (at least as far as I can see) or you could try
val q = for {
altasBajas <- tabla.filter(_.idCliente === id)
if !altasBajas.fechaFin.isNull || altasBajas.fechaFin < DateTime.now
} yield altasBajas

in Slick 3.0, how to I get from a query to a case class?

I am trying to use Slick for database in a Scala application, and running into some issues (or my misunderstandings) of how to query (find) and convert the result to a case class.
I am not mapping the case class, but the actual values, with the intent of creating the case class on the fly. so, my table is:
object Tables {
class Names(tag: Tag) extends Table[Name](tag, "NAMES") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def first = column[String]("first")
def middle = column[String]("last")
def last = column[String]("last")
def * = (id.?, first, middle.?, last) <> ((Name.apply _).tupled, Name.unapply)
}
object NamesQueries {
lazy val query = TableQuery[Names]
val findById = Compiled { k: Rep[Long] =>
query.filter(_.id === k)
}
}
}
and here is the query:
object NamesDAO {
def insertName(name: Name) {
NamesQueries.query += name.copy(id = None)
}
def findName(nameId: Long) = {
val q = NamesQueries.findById(nameId) // AppliedCompiledFunction[Long, Query[Tables.Names, Tables.Names.TableElementType, Seq],Seq[Tables.Names.TableElementType]]
val resultSeq = Database.forConfig("schoolme").run(q.result) // Future[Seq[Tables.Names.TableElementType]]
val result = resultSeq.map { r => // val result: Future[(Option[Long], String, Option[String], String) => Name]
val rr = r.map{ name => // val rr: Seq[(Option[Long], String, Option[String], String) => Name]
Name.apply _
}
rr.head
}
result
}
}
however, the findName method seems to return Future((Option[Long], String, Option[String], String) => Name) instead of a Future(Name). What am i doing wrong? Is it just a matter of just using asInstanceOf[Name]?
EDIT: expanded findName to smaller chunks with comments for each one, as sap1ens suggested.
well, i'll be damned.
following sap1ens comment above, I broke findName to multiple steps (and edited the question). but after that, i went back and gave my val an explicit type, and that worked. see here:
def findName(nameId: Long) = {
val q = NamesQueries.findById(nameId)
val resultSeq: Future[Seq[Name]] = Database.forConfig("schoolme").run(q.result)
val result = resultSeq.map { r =>
val rr = r.map{ name =>
name
}
rr.head
}
result
}
so, type inference was the (/my) culprit this time. remember, remember.

SLICK How to define bidirectional one-to-many relationship for use in case class

I am using SLICK 1.0.0-RC2. I have defined the following two tables Directorate and ServiceArea where Directorate has a one to many relationship with ServiceArea
case class Directorate(dirCode: String, name: String)
object Directorates extends Table[Directorate]("DIRECTORATES") {
def dirCode = column[String]("DIRECTORATE_CODE", O.PrimaryKey)
def name = column[String]("NAME")
def * = dirCode ~ name <> (Directorate, Directorate.unapply _)
}
case class ServiceArea(areaCode: String, dirCode: String, name: String)
object ServiceAreas extends Table[ServiceArea]("SERVICE_AREAS") {
def areaCode = column[String]("AREAE_CODE", O.PrimaryKey)
def dirCode = column[String]("DIRECTORATE_CODE")
def name = column[String]("NAME")
def directorate = foreignKey("DIR_FK", dirCode, Directorates)(_.dirCode)
def * = areaCode ~ dirCode ~ name <> (ServiceArea, ServiceArea.unapply _)
}
To make the Directorate case class useful in my Play application form I am trying to redefine the Directorate case class to have a Seq of ServiceAreas that are related to that Directorate.
case class Directorate(dirCode: String, name: String, serviceAreas: Seq[ServiceArea])
My problem is now with the Directorate table projection. I have attempted to create a method in Directorates:
def serviceAreas = (for { a <- ServiceAreas
if (a.dirCode === dirCode)
} yield (a)).list map {
case t: ServiceArea => t
}
so that I can try something like
def * = dirCode ~ name ~ serviceAreas <> (Directorate, Directorate.unapply _)
but this cannot not work as serviceAreas only goes one way.
It seems reasonable to me that for the Directorate case class to be a useful domain object that it should be able contain the related ServiceAreas.
I'm wondering how I should traverse the inverse relationship so that Directorate table projection will work.
I'm sure there is a more elegant solution, but this should do the trick:
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession
object SlickExperiments2 {
Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
(Directorates.ddl ++ ServiceAreas.ddl).create
case class Directorate(dirCode: String, name: String) {
def serviceAreas: Seq[ServiceArea] = (for {
a <- ServiceAreas
if (a.dirCode === dirCode)
} yield (a)).list
}
object Directorates extends Table[Directorate]("DIRECTORATES") {
def dirCode = column[String]("DIRECTORATE_CODE", O.PrimaryKey)
def name = column[String]("NAME")
def * = dirCode ~ name <> (Directorate, Directorate.unapply _)
}
case class ServiceArea(areaCode: String, dirCode: String, name: String)
object ServiceAreas extends Table[ServiceArea]("SERVICE_AREAS") {
def areaCode = column[String]("AREAE_CODE", O.PrimaryKey)
def dirCode = column[String]("DIRECTORATE_CODE")
def name = column[String]("NAME")
def directorate = foreignKey("DIR_FK", dirCode, Directorates)(_.dirCode)
def * = areaCode ~ dirCode ~ name <> (ServiceArea, ServiceArea.unapply _)
}
Directorates.insert(Directorate("Dircode", "Dirname"))
ServiceAreas.insertAll(ServiceArea("a", "Dircode", "A"), ServiceArea("b", "Dircode", "B"))
val sa = (for{
d <- Directorates
} yield d).list map { case t: Directorate => t.serviceAreas}
println(sa)
}
//> List(List(ServiceArea(a,Dircode,A), ServiceArea(b,Dircode,B)))
}