2016-07-24 6 views
0

この質問は以前のquestionに関連しています。しかし、その質問は閉じているので、私は別のものを作成しなければなりません。 ユースケースはこれです:私は5列のテーブルを持っています。レコードを作成するときは、2列しか必要ありません。後で、ユーザーは同じレコードにさらに情報を追加します。例えば、以下の構造を有するユーザテーブル:id |電話|電子メール|クレジット|レベル。ユーザーが登録するとき、私は自分の電子メールアドレスだけが必要です。ユーザーはIDと電子メールで作成されます。後で、ユーザーは電話番号、クレジットを追加したい、システムもこのユーザーが十分なクレジットを持っているときにレベルを更新します。 私も、私は、私は右のオプションのカラムを使用してphantom dslのオプションの列の使い方は?

sealed class Users extends CassandraTable[Users, User] { 
    object id extends UUIDColumn(this) with PartitionKey[UUID] 

    object phone extends OptionalStringColumn(this) 

    object email extends OptionalStringColumn(this) 

    object credit extends OptionalDoubleColumn(this) 

    object level extends OptionalStringColumn(this) 

    def fromRow(row: Row): User = { 
     User(id(row), phone(row), email(row), credit(row), level(row)) 
    } 
} 

アムいる?

case class User(id:UUID, phone:Option[String], email:Option[String], 
    credit:Option[Double], level:Option[String] 

を作成 ユーザーが1つまたは複数の特定の列を更新しているユースケースについて、どのように進めるべきですか?私はあなたがIDからテーブルを読み、既存の列の値を持つUserオブジェクトを作成し、新しい値を追加して、レコードを更新する必要があるため、この方法がうまく動作しないこの

よう
def updateUser(u: User): Future[ResultSet] = { 
    update.where(_.id eqs u.id).modify(_.phone setTo u.phone) 
     .and(_.email setTo u.email) 
     .and(_.credit setTo u.credit) 
     .and(_.level setTo u.level) 
     .consistencyLevel_=(ConsistencyLevel.QUORUM) 
     .future() 
    } 

を更新方法を試してみました。また、更新メソッドに多くの条件を記述することも現実的ではありません。私がたくさんの列を持っていて、各列を別々に更新できるなら、可能な値の組合せの巨大なリストを書く必要があります。以下の方法が働く可能性があります

if(u.phone != None) update.where(_.id eqs u.id).modify(_.phone setTo u.phone).future 
    if(u.email != None) update.where(_.id eqs u.id).modify(_.email setTo u.email).future 
    if(u.credit != None) update.where(_.id eqs u.id).modify(_.credit setTo u.credit).future 
    ...... 

しかし、私はあなたがそれぞれの更新に更新失敗を処理する場合、それは悪夢となりますので、それは良い習慣であることを確認していません。オプションの列を使用して必要なものを達成するにはどうすればよいですか?

答えて

1

Phantomのクエリは、.futureまたは.oneのようなものを呼び出すことによって実現するまで、クラスです。最低レベルでは、... matchまたはifステートメントを使用して醜いと退屈のようなものだ

def updateUser(u: User): Future[ResultSet] = { 
    val baseQuery = update.where(_.id eqs u.id).modify(_.phone setTo u.phone) 

    val query2 = u.email match { 
    case Some(email) => baseQuery.and(_.email setTo email) 
    case None => baseQuery // don't do anything if none! 
    } 

    // ... 

    query5.future() 
} 

をクエリを構築することができますが、それは作業を行います。

タイプがEitherのモデルを持っていたときも同様の状況に遭遇しました。私はPhantomDSLの少しの拡張を書いてしまいましたが、これはおそらく私が公式化してコミットするべきですが、上記の混乱をきれいに解消します。 INSERTでしたが、UPDATEについて同じことをしたい場合は、これがどれほど簡単かを知ることができます。難しい部分はmodifyandを扱うだろうが、私は彼らがカバーの下で同じ操作をしているソースで掘り下げていると確信していて、違いは唯一の美的です。使用の際に

table.insert 
    .value(_.foo, "foo") 
    .valueOpt(_.bar, Some("bar")) 
    .valueIf(_.buz, x, x.nonEmpty) 
    .matchOn(someEither) { 
    case (Left(Person(name, age), insert) => insert 
     .value(_.personName, name) 
     .value(_.personAge, age) 
    case (Right(Company(name, employeeCount), insert) => insert 
     .value(_.companyName, name) 
     .value(_.companyAge, age) 
    } 
    .future() 

出典:

class RichInsert[T <: CassandraTable[T, _], R, S <: ConsistencyBound, P <: HList](val insert: InsertQuery[T,R,S,P]) { 

    def value[RR](col: T => AbstractColumn[RR], value: RR): RichInsert[T,R,S,P] = 
    new RichInsert(insert.value(col, value)) 

    def valueIf[RR](col: T => AbstractColumn[RR], value: RR, clause: => Boolean): RichInsert[T,R,S,P] = { 
    if (clause) RichInsert(insert.value(col, value)) 
    else this 
    } 

    def valueOpt[RR](col: T => AbstractColumn[RR], value: Option[RR]): RichInsert[T,R,S,P] = { 
    value match { 
     case Some(rr) => RichInsert(insert.value(col, rr)) 
     case None => this 
    } 
    } 

    def matchOn[A](value: A)(pf: PartialFunction[(A, RichInsert[T,R,S,P]), RichInsert[T,R,S,P]]) = 
    if (pf.isDefinedAt((value, this))) pf.apply((value, this)) 
    else this 
} 

object RichInsert { 
    def apply[T <: CassandraTable[T, _], R, S <: ConsistencyBound, P <: HList](insert: InsertQuery[T,R,S,P]): RichInsert[T,R,S,P] = 
    new RichInsert(insert) 
} 

implicit def insertQueryToRichInsert[T <: CassandraTable[T, _], R, S <: ConsistencyBound, P <: HList](insert: InsertQuery[T,R,S,P]): RichInsert[T,R,S,P] = 
    RichInsert(insert) 

編集 - 私は言及を忘れてしまった

ことの一つは、であるあなたの代わりに行うcolumn(row)を行うためのデータをリードバックするときcolumn.parse(row)。あなたはTry[A]を取得し、そこからcolumn.parse(row).toOptionを行うことができます。覚えがたいですが、フローコントロールの例外を使用する必要がないように、カラムを試して読み込む前にカラムが定義されているかどうかをチェックする機能があると思います。

+1

' column.parse(行).toOption'が自動的に追加されます。コレクションのようなものは、 'Optional'を必要とせずに自動的に空になるでしょう。 – flavian

2

ファントム1.28.5では、新しいオプションのsetIfDefined演算子を使用して、目的のものを得ることができます。Update句は、定義されているオプションのみを考慮します。

あなたの更新方法について次のようになります。あなたが `Optional`列を使用することを選択したとき

def updateUser(u: User): Future[ResultSet] = { 
    update.where(_.id eqs u.id).modify(_.phone setTo u.phone) 
    .and(_.email setIfDefined u.email) 
    .and(_.credit setIfDefined u.credit) 
    .and(_.level setIfDefined u.level) 
    .consistencyLevel_=(ConsistencyLevel.QUORUM) 
    .future() 
} 
関連する問題