2

私は主にC#LINQ/SQLに似たDSLを構築する方法についてscalaを調べてきました。C#LINQクエリプロバイダーと連携したことで、LINQクエリを独自のデータストアスクリプトに変換する独自のカスタムクエリプロバイダーを簡単に導入できました。たとえば、scalaで似たようなものを探しています。

 val query = select Min(Close), Max(Close)
 from   StockPrices 
 where  open > 0 

まず第一に、これは内部DSLを使用してscalaで実現することさえ可能です。

この点に関する考え/アイデアは高く評価されています。

私はまだScalaスペースに慣れていませんが、Scala MetaProgramming&Slickを調べ始めました。Slickに対する私の不満は、DSLをSQLクエリに近づけたいということです-上記の構文と同様です。

4

3 に答える 3

3

提供した例とまったく同じように見える内部DSL(現在のリリース)を作成する方法はありません。

この回答からまだ持っているマクロを使用すると、(比較的高速に)取得できる最も近いものは次のとおりです。

select(Min(StockPrices.Open), Max(StockPrices.Open))
  .from(StockPrices)

ソリューションのreal作成にはかなりの時間がかかります。あなたがそれを喜んでするなら、あなたはマクロを使ってかなり遠くまで来ることができます(単純なトピックではありません)。

まったく同じ構文が本当に必要な場合は、「無料」で日食ベースのエディタを使用してDSLを作成できるXTextのようなものをお勧めします。

上記の例に必要なコード(前述のマクロは含まれていません):

trait SqlElement {
  def toString(): String
}

trait SqlMethod extends SqlElement {
  protected val methodName: String
  protected val arguments: Seq[String]

  override def toString() = {
    val argumentsString = arguments mkString ","
    s"$methodName($argumentsString)"
  }
}

case class Select(elements: Seq[SqlElement]) extends SqlElement {
  override def toString() = s"SELECT ${elements mkString ", "}"
}

case class From(table: Metadata) extends SqlElement {
  private val tableName = table.name
  override def toString() = s"FROM $tableName"
}
case class Min(element: Metadata) extends SqlMethod {
  val methodName = "Min"
  val arguments = Seq(element.name)
}
case class Max(element: Metadata) extends SqlMethod {
  val methodName = "Max"
  val arguments = Seq(element.name)
}

class QueryBuilder(elements: Seq[SqlElement]) {
  def this(element: SqlElement) = this(Seq(element))

  def from(o: Metadata) = new QueryBuilder(elements :+ From(o))
  def where(element: SqlElement) = new QueryBuilder(elements :+ element)
  override def toString() = elements mkString ("\n")
}

def select(args: SqlElement*) = new QueryBuilder(Select(args))

trait Column
object Column extends Column

object tables {

  object StockPrices$ {
    val Open: Column = Column
    val Close: Column = Column
  }
  val StockPrices = StockPrices$
}

そしてそれを使用するには:

import tables._
import StockPrices._

select(Min(StockPrices.Open), Max(StockPrices.Open))
  .from(StockPrices)
  .toString
于 2013-03-26T21:33:30.927 に答える
1

これは立派なプロジェクトですが、着手され、一般リリースで利用できるプロジェクトです。

もちろん、私はスリックについて話している。

于 2013-03-26T17:58:03.657 に答える
1

Scala / Javaの相互運用性がそれほど問題ではなく、提案した構文と比較していくつかの構文の癖がある内部DSLを使用する場合は、jOOQが人気のある代替手段になりつつあります。スリックjOOQマニュアルの例:

for (r <- e
    select (
      T_BOOK.ID * T_BOOK.AUTHOR_ID,
      T_BOOK.ID + T_BOOK.AUTHOR_ID * 3 + 4,
      T_BOOK.TITLE || " abc" || " xy"
    )
    from T_BOOK
    leftOuterJoin (
      select (x.ID, x.YEAR_OF_BIRTH)
      from x
      limit 1
      asTable x.getName()
    )
    on T_BOOK.AUTHOR_ID === x.ID
    where (T_BOOK.ID <> 2)
    or (T_BOOK.TITLE in ("O Alquimista", "Brida"))
    fetch
) {
  println(r)
}
于 2014-03-08T16:19:14.693 に答える