Search code examples
scalaplayframeworkcrudslick

Update and delete queries not working in play-slick


Iam trying to write a simple CRUD application for play-slick. I can Insert into the database and display all users, but I cannot update or delete users. My entire code is below

package models

import javax.inject.{ Inject, Singleton }
import play.api.db.slick.DatabaseConfigProvider
import slick.jdbc.JdbcProfile

import scala.concurrent.{ Future, ExecutionContext }

/**
 * A repository for people.
 *
 * @param dbConfigProvider The Play db config provider. Play will inject this for you.
 */
@Singleton
class PersonRepository @Inject() (dbConfigProvider: DatabaseConfigProvider)(implicit ec: ExecutionContext) {
  // We want the JdbcProfile for this provider
  private val dbConfig = dbConfigProvider.get[JdbcProfile]

  // These imports are important, the first one brings db into scope, which will let you do the actual db operations.
  // The second one brings the Slick DSL into scope, which lets you define the table and other queries.
  import dbConfig._
  import profile.api._

  /**
   * Here we define the table. It will have a name of people
   */
  private class PeopleTable(tag: Tag) extends Table[Person](tag, "people") {

    /** The ID column, which is the primary key, and auto incremented */
    def id = column[Long]("id", O.PrimaryKey, O.AutoInc)

    /** The name column */
    def name = column[String]("name")

    /** The age column */
    def age = column[Int]("age")

    /**
     * This is the tables default "projection".
     *
     * It defines how the columns are converted to and from the Person object.
     *
     * In this case, we are simply passing the id, name and page parameters to the Person case classes
     * apply and unapply methods.
     */
    def * = (id, name, age) <> ((Person.apply _).tupled, Person.unapply)
  }

  /**
   * The starting point for all queries on the people table.
   */
  private val people = TableQuery[PeopleTable]

  /**
   * Create a person with the given name and age.
   *
   * This is an asynchronous operation, it will return a future of the created person, which can be used to obtain the
   * id for that person.
   */
  def create(name: String, age: Int): Future[Person] = db.run {
    // We create a projection of just the name and age columns, since we're not inserting a value for the id column
    (people.map(p => (p.name, p.age))
      // Now define it to return the id, because we want to know what id was generated for the person
      returning people.map(_.id)
      // And we define a transformation for the returned value, which combines our original parameters with the
      // returned id
      into ((nameAge, id) => Person(id, nameAge._1, nameAge._2))
    // And finally, insert the person into the database
    ) += (name, age)
  }

  /**
   * List all the people in the database.
   */
  def list(): Future[Seq[Person]] = db.run {
    people.result
  }

  def del(id: Int) : Future[Seq[Person]] = db.run {
   people.filter(_.id === id).delete

  }

  def update (id: Int, name: String) : Future[Seq[Person]] = {
    db.run(people.filter(_.id === id).update("john"))

  }
}

It might also be possible that I have excluded some imports, so please check to see if i need to import anything.

I also get this error and I don't know what it means:

type mismatch; found : UserData.this.dbConfig.profile.ProfileAction[Int,slick.dbio.NoStream,slick.dbio.Effect.Write] (which expands to) slick.sql.FixedSqlAction[Int,slick.dbio.NoStream,slick.dbio.Effect.Write] required: slick.dbio.DBIOAction[Seq[models.User],slick.dbio.NoStream,Nothing]


Solution

  • I think you are having a problem with the return types when you delete or update. AFAIK they return the number of rows that have been modified.

    Try this:

    def del(id: Int) : Future[Int] = db.run {
      people.filter(_.id === id).delete
    }
    
    def update (id: Int, name: String) : Future[Int] = {
      db.run(people.filter(_.id === id).update("john"))
    }