2012-06-03 4 views
13

Ho difficoltà a comporre diversi componenti di query in una singola query. Il mio obiettivo è creare un insieme di tratti (ad esempio SoftDeletable, HasName, SortedByName, WithTimestamps) che posso semplicemente mixare in oggetti Table per aggiungere questo comportamento.Come posso comporre query in ScalaQuery per creare tratti riutilizzabili?

L'ideale sarebbe simile:

abstract class BaseModel[Tuple <: Product,CaseClass](tableName: String) 
    extends Table[Tuple](tableName) { 
    def id = column[Int]("id", O.AutoInc, O.PrimaryKey) 

    def mapped: MappedProjection[CaseClass, TupleClass] 

    def allQuery = this.map(_.mapped) 
    final def all = database.withSession { implicit session: Session => 
    allQuery.list() 
    } 

    ... 
} 

trait SoftDeletable[Tuple <: Product, CaseClass] 
    extends BaseModel[Tuple,CaseClass] { 
    def isActive = column[String]("is_active") 

    def * = super.* ~ isActive 
    def allQuery = /* here, I'd like to compose super.allQuery 
        with a filter that returns rows where isActive is true */ 
} 

trait HasName[Tuple <: Product] extends Table[Tuple] { 
    def name = column[String]("name") 

    def * = super.* ~ name 
} 

trait SortedByName[Tuple <: Product] extends HasName[Tuple { 
    override def allQuery = super.allQuery /* compose somehow 
              with (_ <- Query orderBy name */ 
} 

Posso fare questo genere di cose con ScalaQuery? I principali punti critici sono:

  1. Come faccio a modo pulito compongo i filtri in SoftDeletable.allQuery e l'ordinamento in SortedByName.allQuery con BaseModel.allQuery?

  2. Con l'aggiunta di colonne nelle implementazioni delle sottoclassi del metodo *, il parametro di tipo tupla per Table non ultime partite - c'è un modo per questi tratti di aggiungere in modo incrementale nuovi tipi alle colonne tupla nella classe ultimo concreto? (Non mi aspetto che ci sia, ma sarebbe bello se ci fosse qualcosa che mi manca).

  3. Ho bisogno di ripetere la dichiarazione lunga tupla in ogni tratto, che diventa molto ingombrante se un tavolo ha cinque o sei colonne. C'è qualcosa che posso fare con i membri di tipo per evitare di dover fare le cose come:

    case class Foo 
    
    class Foos[(Int,Int,Boolean,String), Foo] extends 
        Table[(Int,Int,Boolean,String)] with 
        SoftDeletable[(Int,Int,Boolean,String), Foo] with 
        SortedByName[(Int,Int,Boolean,String), Foo] with 
        HasName[(Int,Int,Boolean,String)] { 
    } 
    

Posso evitare tutto questo ripetersi? Sulla base di un suggerimento da jesnor su IRC, sono stato in grado di evitare alcune di queste in questo modo:

abstract class SoftDeletableBaseModel[TupleClass <: Product, CaseClass](tableName: String) 
     extends BaseModel[TupleClass, CaseClass](tableName) 
     with SoftDeletable[TupleClass,CaseClass] 

In altre parole, mediante la combinazione di tratti specifici insieme, non ho bisogno di ripetere l'intera dichiarazione tupla; ovviamente, lo svantaggio è che non è più possibile un facile mix-in di vari tratti - ho bisogno di creare molte sottoclassi specifiche per evitare questa ripetizione. C'è un altro modo?

Aggiornamento: mi sono reso conto che non è necessario utilizzare parametri di tipo CaseClass e TupleClass separati. Dal momento che implementano classi case Product*, si può solo passare il nome della classe caso in Tavola, che risolve il problema in 3:

trait SoftDeletable[CaseClass] extends BaseModel[CaseClass] { ... } 

class Models extends BaseModel[Model]("models") with SoftDeletable[Model] { ... } 
+0

Non è una risposta per sé, ma se si può avere una funzione da un tipo di tabella che restituisce le sue colonne, per entrambi i caratteri, e poi combinarle (f1, f2) => (t: table.type) => (f1 (t), f2 (t)), hai una funzione che puoi passare alla mappa, che sarà equivalente a table.map (t => ((trait1col2, trait1col2), (trait2col1, trait2col2))) . – nafg

+0

Btw Sto provando ad affrontare parte di questo problema qui: http://stackoverflow.com/questions/11408072/trouble-getting-scala-type-inference-to-work – nafg

risposta

1

Se il vostro problema è solo l'aggiunta del genere, non è solo una questione di flatMap?

def sortBy[T,U,C](q: Query[T,U], col: NamedColumn[C]) = q.flatMap(_ => Query orderBy col)