是否可以为Acolyte ScalaCompositeHandler参数化查询或参数?

时间:2018-10-09 19:26:07

标签: sql scala jdbc

背景:

我尝试完成此处定义的问题,但未能成功。 Acolyte要求您定义要在匹配表达式中处理的查询和参数,并且必须在编译时知道匹配表达式中使用的值。 (但是请注意,this StackOverflow答案似乎提供了解决此限制的方法。)

如果这确实不可能,那么就我的用例而言,无法动态定义Acolyte的参数和查询将严重限制该框架。我怀疑这也会对其他人构成限制。

曾在少数几个问题中主张使用Acolyte的SO用户表示in this comment,可以动态定义查询及其响应。因此,我打开了这个问题,邀请其他人证明自己的情况。

问题

使用Acolyte,我希望能够封装用于匹配查询并生成其响应的逻辑。这是一个理想的功能,因为我想保持代码干燥。换句话说,我正在寻找类似以下伪代码的东西:

def generateHandler(query: String, accountId: Int, parameters: Seq[String]): ScalaCompositeHandler = AcolyteDSL.handleQuery {
  parameters.foreach(p =>
    // Tell the handler to handle this specific parameter
    case acolyte.jdbc.QueryExecution(query, ExecutedParameter(accountId) :: ExecutedParameter(p) :: Nil) =>
      someResultFunction(p)
  )
}

在Acolyte中这可能吗?如果是这样,请提供示例。

1 个答案:

答案 0 :(得分:0)

通过使用模式匹配,确实可以对查询和/或参数进行参数化。

有关示例,请参见下面的代码

import java.sql.DriverManager

import acolyte.jdbc._
import acolyte.jdbc.Implicits._
import org.scalatest.FunSpec

class AcolyteTest extends FunSpec {
  describe("Using pattern matching to extract a query parameter") {
    it("should extract the parameter and make it usable for dynamic result returning") {
      val query = "SELECT someresult FROM someDB WHERE id = ?"

      val rows = RowLists.rowList1(classOf[String] -> "someresult")

      val handlerName = "testOneHandler"
      val handler = AcolyteDSL.handleQuery {
        case acolyte.jdbc.QueryExecution(`query`, ExecutedParameter(id) :: _) =>
          rows.append(id.toString)
      }

      Driver.register(handlerName, handler)
      val connection = DriverManager.getConnection(s"jdbc:acolyte:anything-you-want?handler=$handlerName")
      val preparedStatement = connection.prepareStatement(query)

      preparedStatement.setString(1, "hello world")
      val resultSet = preparedStatement.executeQuery()    
      resultSet.next()    
      assertResult(resultSet.getString(1))("hello world")

    }

    it("should support a slightly more complex example") {
      val firstResult = "The first result"
      val secondResult = "The second result"

      val query = "SELECT someresult FROM someDB WHERE id = ?"

      val rows = RowLists.rowList1(classOf[String] -> "someresult")

      val results: Map[String, RowList1.Impl[String]] = Map(
        "one" -> rows.append(firstResult),
        "two" -> rows.append(secondResult)
      )

      def getResult(parameter: String): QueryResult = {
        results.get(parameter) match {
          case Some(row) => row.asResult()
          case _ => acolyte.jdbc.QueryResult.Nil
        }
      }

      val handlerName = "testTwoHandler"
      val handler = AcolyteDSL.handleQuery {
        case acolyte.jdbc.QueryExecution(`query`, ExecutedParameter(id) :: _) =>
          getResult(id.toString)
      }

      Driver.register(handlerName, handler)
      val connection = DriverManager.getConnection(s"jdbc:acolyte:anything-you-want?handler=$handlerName")
      val preparedStatement = connection.prepareStatement(query)

      preparedStatement.setString(1, "one")
      val resultSetOne = preparedStatement.executeQuery()
      resultSetOne.next()
      assertResult(resultSetOne.getString(1))(firstResult)

      preparedStatement.setString(1, "two")
      val resultSetTwo = preparedStatement.executeQuery()
      resultSetTwo.next()
      assertResult(resultSetTwo.getString(1))(secondResult)
    }
  }
}