Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I compose queries in ScalaQuery in order to create reusable traits?

I'm having some trouble composing different query components into a single Query. My goal is to create a set of traits (e.g. SoftDeletable, HasName, SortedByName, WithTimestamps) that I can simply mix-in to Table objects to add that behavior.

The ideal would look like:

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 */
}

Can I do these kinds of things with ScalaQuery? The main sticking points are:

  1. How do I cleanly compose the filters in SoftDeletable.allQuery and the sort in SortedByName.allQuery with BaseModel.allQuery?

  2. By adding columns in subclass implementations of the * method, the tuple type parameter to Table no latter matches - is there a way for these traits to incrementally add new types to the columns tuple in the ultimate concrete class? (I don't expect there to be, but it would be nice if there was something I'm missing).

  3. I need to repeat the long tuple declaration in every trait, which becomes very unwieldy if a table has five or six columns. Is there something I can do with type members to avoid having to do things like:

    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)] {
    }
    

Can I avoid all this repetition? Based on a suggestion from jesnor on IRC, I was able to avoid some of this like so:

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

In other words, by combining specific traits together, I don't need to repeat the entire tuple declaration; of course, the disadvantage is that easy mixing-in of various traits is no longer possible - I need to create lots of specific subclasses to avoid this repetition. Is there another way?

Update: So I realized that I don't need to use separate CaseClass and TupleClass type parameters. Since case classes implement Product*, you can just pass the case class name into Table, which solves the problem in 3:

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

class Models extends BaseModel[Model]("models") with SoftDeletable[Model] { ... }
like image 679
Bill Avatar asked Jun 03 '12 23:06

Bill


People also ask

How to make a reusable structure in Query Designer?

Similarly, you can make reusable structures that you use in a query local. At least one InfoProvider that is filled with data must be available in the BW system. ... 1. Start the Query Designer and choose Query → New Query in the menu bar. 2. You get to the selection screen for all InfoProviders for which you can define a new query.

How to create a new query in the query designer?

Start the Query Designer and choose Query → New Query in the menu bar. 2. You get to the selection screen for all InfoProviders for which you can define a new query.

How to make a local structure from an existing query?

Local structures are used in only one query. You can make local structures from any existing query reusable. Similarly, you can make reusable structures that you use in a query local. At least one InfoProvider that is filled with data must be available in the BW system. ... 1. Start the Query Designer and choose Query → New Query in the menu bar.

What are the features of sap query?

SAP Query offers users a broad range of ways to define reporting programs and create different types of reports such as basic lists, statistics, and ranked lists. SAP Query – Features: Following are the major components which are associated with SAP Query: Info Sets – Are base for the Query and it contains one or more database table details


1 Answers

If your issue is only adding the sort, isn't it just a matter of flatMap?

def sortBy[T,U,C](q: Query[T,U], col: NamedColumn[C]) = q.flatMap(_ => Query orderBy col)
like image 125
nafg Avatar answered Oct 25 '22 09:10

nafg