Search code examples
scalagenericstraitssqueryl

Scala Data Modeling and Generics


I'm using the Play Framework and Squeryl to make a fairly basic front end for a database, but I know I'm rewriting too much code. I have different models to represent data in my db, and they all do the same six functions

object ModelType{
    def add(model:ModelType):Option[ModelType] = Option(AppDB.tablename.insert(model))
    def remove(id: Long) = AppDB.tablename.delete(id)
    def getAll():List[ModelType] = from(AppDB.tablename)(model => select(model) orderBy(model.aDifferentFieldForEachModel)) toList
    def toJson(model:ModelType):JsValue ={
      Json.toJson(
      Map("field" -> Json.toJson(model.field))
      )
    }
    def allToJson() = {
      val json:List[JsValue] = getAll.map{toJson(_)}
      Json.toJson(json.toSeq)
    }
    def validate(different values for each model) = // is fairly different for each one. Validates the submitted fields from a user
}

So I'm using case classes for each of the models, and using an accompanying object for these commands. How can I use generics or traits in scala to make my life easier and not type all of these methods out every time?

EDIT: Mostly solved with gzm0's answer, but the problem is now how would I implement getAll in the trait? I want to be able to save some variable for each model that resembles the model.aDifferentFieldForEachModel as above.


Solution

  • You could try the following:

    trait ModelOps[T] {
      def table: AppDB.Table // not sure about type
      def order: AppDB.OrderByPredicate // not sure about type
      def toJson(model: T): JsValue
    
      def add(model: T): Option[T] = Option(AppDB.categories.insert(model))
      def remove(id: Long) = AppDB.categories.delete(id)
      def getAll(): List[T] = from(table)(model => select(model) orderBy(order)) toList
      def allToJson() = {
        val json:List[JsValue] = getAll.map{toJson(_)}
        Json.toJson(json.toSeq)
      }
    
    }
    

    Then you can for each model type:

    object ModelType extends ModelOps[ModelType] {
      def table = AppDB.examples
      def order = yourPredicate
      def toJson(model:ModelType):JsValue = {
        Json.toJson(Map("field" -> Json.toJson(model.field)))
      }
      def validate(different values for each model) = // is fairly different for each one. Validates the submitted fields from a user
    }
    

    UPDATE About the true type of AppDB.OrderByPredicate:

    Calling select on PrimitiveTypeMode returns a SelectState. On this SelectState, you will call orderBy which takes a List[BaseQueryYield#O] (or multiple of those in the same argument list). Hence you should define:

    def order(model: T): List[BaseQueryYield#O]
    

    and

    def getAll() = from(table)(model => select(model) orderBy(order(model))) toList
    

    By the way, BaseQueryYield#O resolves to ExpressionNode.