Search code examples
postgresqlscalabatch-processingslick

Insert records in batch Slick


I want to insert more than 10 rows of data into the Task table, so I have created a list of these records. Except for my table, I have a repository with functions like create, update and so on. So I can use create a function to add one record but I want to use this function to insert data in batch.

case class Task (
  idTask: Option[Long],
  ownerId: Long,
  name: String,
  finished: Boolean
)

class TaskTable(tag: Tag) extends Table[Task](tag, "tasks"){
  val idTask = column[Long]("id_task", O.PrimaryKey)
  val ownerId = column[Long]("owner")
  val name = column[String]("name")
  val finished = column[Boolean]("finished")

  val ownerFk = foreignKey("owner_id_fk", ownerId, TableQuery[UserTable])(_.idUser)

  def * = (idTask.?, ownerId, name, finished) <> (Task.apply _ tupled, Task.unapply)
}

object TaskTable{
  lazy val table = TableQuery[TaskTable]
}

class TaskRepository(db: Database) {
  val taskTableQuery = TableQuery[TaskTable]
  def create(task: Task): Future[Task] =
    db.run(taskTableQuery returning taskTableQuery += task)

 def createTasks(tasks: List[Task]): Future[Option[Task]] = 
    db.run(taskTableQuery ++= tasks)

  def update(task: Task): Future[Int] =
    db.run(taskTableQuery.filter(_.idTask === task.idTask).update(task))

  def delete(task: Task): Future[Int] =
    db.run(taskTableQuery.filter(_.idTask === task.idTask).delete)

  def getById(task: Task): Future[Option[Task]] =
    db.run(taskTableQuery.filter(_.idTask === task.idTask).result.headOption)
}

I have tried to do something like this:

val tasks = List(
    Task(Some(1),  1,"Analyze logs with Spark", false),
    Task(Some(2),  1,"Clean and process data", false),
...
)
val createTasks = tasks.map(taskRepository.create(_))

But this createTasks value has type Unit and I can not run it with db.run or Await.result. My method createTasks does not compile because of the return type mismatch. So how can I create this method for batch insert or change the existing one? I would be very grateful for any help!


Solution

  • If you know the actions at compile time, use DBIO.seq() to chain the DB actions:

    db.run(
      DBIO.seq( taskTableQuery += Task(....), 
                taskTableQuery += Task(....), 
                taskTableQuery += Task(....)...
      ).transactionally
    )
    

    Otherwise, use DBIO.sequence:

    val taskSeq:Seq[Task] = ... however you get the tasks
    db.run( 
        DBIO.sequence( taskSeq.map(t=>taskTableQuery+=t) ).transactionally 
    )