私はこれを試したことはありませんが、あなたが混ぜる特性はどうですか:
trait CommonFields { this: Table[_] =>
def id = column[String]("id", O.PrimaryKey)
def livemode = column[Boolean]("livemode", O.NotNull)
def created = column[DateTime]("created", O.NotNull)
def createdBy = column[Account]("created_by", O.NotNull)
protected common_* = id ~ livemode ~ created ~ createdBy
}
次に、次のことができます。
object AsTable extends Table[(String,Boolean,DateTime,Account,String)]("a_table")
with CommonFields {
def foo = column[String]("foo", O.NotNull)
def * = common_* ~ foo
}
ここで繰り返さなければならないのは、要素の型だけです。
アップデート
オブジェクトマッピングを行いたい場合:
- ケースクラスにマッピングします
- ケースクラスのフィールドは同じ順序です
ただ行う:
case class A(
id: String,
livemode: Boolean,
created: DateTime,
createdBy: Account,
foo: String)
object AsTable extends Table[A]("a_table") with CommonFields {
def foo = column[String]("foo", O.NotNull)
def * = common_* ~ foo <> (A.apply _, A.unapply _)
}
これは最も経済的な解決策のようです (型パラメーターを定義*
しCommonFields
て追加するよりも)。ただし、フィールドが変更された場合は、すべてのケース クラスを変更する必要があります。
ケースクラスでコンポジションを使用することで、これを軽減しようとすることができます。
case class Common(
id: String,
livemode: Boolean,
created: DateTime,
createdBy: Account)
case class A(
common: Common,
foo: String)
ただし、マッパー関数を構築するとき、(どこかで) 次の形式のタプルを変換する必要があります。
(CT_1, CT_2, ... CT_N, ST_1, ST_2, ..., ST_M)
CT
一般的なタイプ (で知られているCommonFields
)
ST
特定のタイプ (で知られているAsTable
)
に:
(CT_1, CT_2, ... CT_N), (ST_1, ST_2, ..., ST_M)
それらをサブルーチンに個別に変換し、タプルとの間で渡すCommon
ためA
。
CT
(で実装する場合AsTable
) またはST
(で実装する場合)の数または正確なタイプを知らなくても、これを行う必要がありますCommonFields
。Scala 標準ライブラリのタプルではそれができません。これを行うには、たとえば shapelessHLists
によって提供されるasを使用する必要があります。
これが努力する価値があるかどうかは疑問です。
基本的なアウトラインは次のようになります (必要となる暗黙の混乱はすべて除きます)。このコードはこのようにはコンパイルされません。
trait CommonFields { this: Table[_] =>
// like before
type ElList = String :: Boolean :: DateTime :: Account :: HNil
protected def toCommon(els: ElList) = Common.apply.tupled(els.tupled)
protected def fromCommon(c: Common) = HList(Common.unapply(c))
}
object AsTable extends Table[A] with CommonFields {
def foo = column[String]("foo", O.NotNull)
def * = common_* ~ foo <> (x => toA(HList(x)), x => fromA(x) tupled)
// convert HList to A
protected def toA[L <: HList](els: L) = {
// Values for Common
val c_els = els.take[Length[ElList]]
// Values for A
val a_els = toCommon(c_els) :: els.drop[Length[ElList]]
A.apply.tupled(a_els.tupled)
}
// convert A to HList
protected def fromA(a: A) =
fromCommon(a.common) :: HList(A.unapply(a)).drop[One]
}
型マジックをさらに使用すると、最後の 2 つの問題を解決できる可能性があります。
toA
andをベーストレイトに入れfromA
ます (トレイトで型パラメーターを使用するか、抽象型メンバーを使用します)。
- この手法を使用し
ElList
てから抽出して明示的に定義することは避けてくださいCommon.apply