9

Scala 用の SQL DSL を作成するのに苦労しています。DSL は、Java の一般的なクエリ抽象化レイヤーであるQuerydslの拡張です。

私は今、次のような本当に単純な表現に苦労しています

user.firstName == "Bob" || user.firstName == "Ann"

Querydsl はここで使用できる式モデルを既にサポートしているため、Proxy オブジェクトから Querydsl 式への変換を提供することにしました。プロキシを使用するために、このようなインスタンスを作成します

import com.mysema.query.alias.Alias._

var user = alias(classOf[User])

次の暗黙的な変換により、プロキシ インスタンスとプロキシ プロパティの呼び出しチェーンを Querydsl 式に変換できます。

import com.mysema.query.alias.Alias._
import com.mysema.query.types.expr._
import com.mysema.query.types.path._

object Conversions {        
    def not(b: EBoolean): EBoolean = b.not()        
    implicit def booleanPath(b: Boolean): PBoolean = $(b);        
    implicit def stringPath(s: String): PString = $(s);        
    implicit def datePath(d: java.sql.Date): PDate[java.sql.Date] = $(d);        
    implicit def dateTimePath(d: java.util.Date): PDateTime[java.util.Date] = $(d);        
    implicit def timePath(t: java.sql.Time): PTime[java.sql.Time] = $(t);            
    implicit def comparablePath(c: Comparable[_]): PComparable[_] = $(c);        
    implicit def simplePath(s: Object): PSimple[_] = $(s);        
}

今、私はこのような式を構築することができます

import com.mysema.query.alias.Alias._
import com.mysema.query.scala.Conversions._

var user = alias(classOf[User])
var predicate = (user.firstName like "Bob") or (user.firstName like "Ann")

以下の問題で悩んでいます。

eqScala のメソッドとして既に利用可能でneあるため、それらが使用されても変換はトリガーされません。

この問題は、次のように一般化できます。eq、ne、startsWith などの Scala 型で既に使用可能なメソッド名を使用する場合、暗黙の変換をトリガーするためにある種のエスケープを使用する必要があります。

以下を検討しています

大文字

var predicate = (user.firstName LIKE "Bob") OR (user.firstName LIKE "Ann")

これは、たとえばCircumflex ORMのアプローチです。これは、同様の DSL の目的を持つ Scala 用の非常に強力な ORM フレームワークです。しかし、このアプローチは、Querydsl では小文字であるクエリ キーワード (select、from、where など) と矛盾します。

いくつかのプレフィックス

var predicate = (user.firstName :like "Bob") :or (user.firstName :like "Ann")

述語使用のコンテキストは次のようなものです

var user = alias(classOf[User])

query().from(user)
    .where( 
      (user.firstName like "Bob") or (user.firstName like "Ann"))
    .orderBy(user.firstName asc)
    .list(user);

Scala の SQL DSL を構築するためのより良いオプションや別のアプローチはありますか?

したがって、質問は基本的に2つのケースに要約されます

  • スーパークラスに存在するメソッドを使用するときに暗黙的な型変換をトリガーすることは可能ですか (例eq)

  • それが不可能な場合、 , のようなメソッドに使用する最も Scalaesque な構文は何でしょうeqne?

編集

エイリアス インスタンスと $-prefix ベースのエスケープ構文を使用して、Querydsl で Scala をサポートしました。結果に関するブログ投稿は次のとおりです。http://blog.mysema.com/2010/09/querying-with-scala.html

4

4 に答える 4

3

Scala Days でとても良い話がありました: Christoph Wulf による Type-safe SQL embedded in Scala です。

こちらのビデオを参照してください: Christoph Wulf による Scala に埋め込まれた型安全な SQL

于 2010-09-09T10:18:07.277 に答える
3

Westkämper 氏 - 私はこの問題を熟考していました.Int や String などの基本的なデータ型がソース情報を含むように拡張され、それらを組み合わせた結果が同様に、それらのソースと組み合わせの性質を自分自身の中に保持します。

たとえば、user.firstName メソッドは、String を拡張する TracerString を返しますが、String がリレーションの列に対応することも示します。== メソッドは、Boolean を拡張した EqualityTracerBoolean を返すように上書きされます。これにより、標準の Scala セマンティクスが保持されます。ただし、EqualityTracerBoolean のコンストラクターは、列と文字列定数との関係を比較することによって式の結果が導出されたという事実を記録します。次に、「where」メソッドは、仮引数に対して評価された条件式によって返された EqualityTracerBoolean オブジェクトを分析して、それを作成するために使用された式を導き出すことができます。

不等式演算子のオーバーライド定義、Int のプラスとマイナス、および SQL から表現したいものすべてと、これらのそれぞれに対応するトレーサー クラスが必要です。ちょっとした企画になります!

とにかく、気にせず、代わりにsquerylを使うことにしました。

于 2010-09-13T17:00:53.187 に答える
3

, の代わりに , など、もう少し冗長な演算子名を使用しているため、 jOOQでまったく同じ問題はありませんでした。一方、jOOQ にはバインド値を明示的に作成するための演算子があり、これをScala のキーワードと同様に でオーバーロードする必要がありました。演算子のオーバーロードはオプションですか? ここで、Scala で jOOQ を実行しようとしたことを文書化しました。equalnotEqualeqnevalvalueval

http://lukaseder.wordpress.com/2011/12/11/the-ultimate-sql-dsl-jooq-in-scala/

あなたと同じように、メジャー リリースではすべてのキーワードを大文字にすることも考えていました ( 、 などを含むSELECT) FROM。しかし、それでは、「複合」キーワードを 2 つのメソッド呼び出しに分割するか、アンダースコアで接続するかについて未解決の問題が残ります:GROUP().BY()またはGROUP_BY(). WHEN().MATCHED().THEN().UPDATE()またはWHEN_MATCHED_THEN_UPDATE()。結果は本当に満足のいくものではないので、そのような修正のために後方互換性を壊す価値はないと.思う(). では、jOOQ と QueryDSL の両方を専用の Scala-API で (「拡張」ではなく) 「ラップ」する必要があるのではないでしょうか?

于 2011-12-24T10:07:14.143 に答える
1

実行時にバイトコードを逆コンパイルするのはどうですか? 私はそのようなツールを書き始めました:

http://h2database.com/html/jaqu.html#natural_syntax

私はそれがハックであることを知っているので、-1に投票しないでください:-)私はそれについて言及したかっただけです。比較的斬新なアプローチです。実行時に逆コンパイルする代わりに、注釈プロセッサを使用してコンパイル時に実行できる可能性がありますが、Scala を使用してそれが可能かどうかはわかりません (実際に Java で可能かどうかはわかりませんが、Project Lombokはそのようなことを行うようです)。

于 2010-09-10T09:56:19.490 に答える