Slick 3.0 - Update columns in a table and return the entire table object?

Here is the implementation for Slick 2.

Slick 2 - Update columns in a table and return the entire table object

Does anyone have any ideas on how to implement this in Slick 3?

+1
sql scala scalaquery slick
source share
1 answer

I was able to do this work by expanding Tim Harper's amazing work in https://stackoverflow.com/a/464829/

Here is what I have done now:

package utils import scala.language.existentials import slick.ast._ import slick.driver.PostgresDriver._ import slick.driver.PostgresDriver.api._ import slick.jdbc.{GetResult, JdbcResultConverterDomain, SetParameter, StaticQuery β‡’ Q, StaticQueryInvoker, StreamingInvokerAction} import slick.profile.SqlStreamingAction import slick.relational.{CompiledMapping, ResultConverter} import slick.util.SQLBuilder object Slick { object UpdateReturning { implicit class UpdateReturningInvoker[E, U, C[_]](updateQuery: Query[E, U, C]) { def updateReturning[A, F](returningQuery: Query[A, F, C], v: U)(implicit db: Database) = { val ResultSetMapping(_, CompiledStatement(_, sres: SQLBuilder.Result, _), CompiledMapping(_updateConverter, _)) = updateCompiler.run(updateQuery.toNode).tree val returningNode = returningQuery.toNode val fieldNames = returningNode match { case Bind(_, _, Pure(Select(_, col), _)) => List(col.name) case Bind(_, _, Pure(ProductNode(children), _)) => children.map { case Select(_, col) => col.name }.toList case Bind(_, TableExpansion(_, _, TypeMapping(ProductNode(children), _, _)), Pure(Ref(_), _)) => children.map { case Select(_, col) => col.name }.toList } implicit val pconv: SetParameter[U] = { val ResultSetMapping(_, compiled, CompiledMapping(_converter, _)) = updateCompiler.run(updateQuery.toNode).tree val converter = _converter.asInstanceOf[ResultConverter[JdbcResultConverterDomain, U]] SetParameter[U] { (value, params) => converter.set(value, params.ps) } } implicit val rconv: GetResult[F] = { val ResultSetMapping(_, compiled, CompiledMapping(_converter, _)) = queryCompiler.run(returningNode).tree val converter = _converter.asInstanceOf[ResultConverter[JdbcResultConverterDomain, F]] GetResult[F] { p => converter.read(p.rs) } } val fieldsExp = fieldNames.map(quoteIdentifier).mkString(", ") val pconvUnit = pconv.applied(v) val sql = sres.sql + s" RETURNING ${fieldsExp}" val unboundQuery = Q.query[U, F](sql) val boundQuery = unboundQuery(v) new StreamingInvokerAction[Vector[F], F, Effect] { def statements = List(boundQuery.getStatement) protected[this] def createInvoker(statements: Iterable[String]) = new StaticQueryInvoker[Unit, F](statements.head, pconvUnit, (), rconv) protected[this] def createBuilder = Vector.newBuilder[F] }.asInstanceOf[SqlStreamingAction[Vector[F], F, Effect]] } } } } 

Then its code converts StaticQuery to SqlStreamingAction

 import utils.Slick.UpdateReturning._ val update = Users.filter(_.id === 1).map(_.firstName). updateReturning(Users.map(_.firstName), ("Jane")) val firstName = db.run(update.headOption).futureValue.get firstName must === ("Jane") 
+6
source share

All Articles