2
votes

I know there are other questions in stack overflow, but None of them works for me.

I'm trying to map a simple inheritance in slick projection

I try hundreds of combinations, I can't make this compile. I end of with the follow code and the error bellow.

I simplify the case classes because they have much more data. Without inheritance my other layers (controllers, services and interface) will have to deal with complexity, because in this case the model represents real objects that are in trisect inherited, there is no better representation that inheritance for this classes. In the service and controller layer I make the Json representation of the classes be exacted what I need, I can send and consume a Json API that represents my model, the only thing in the way is persisting this representation in relational database, my relational model is capable of persist this entities in an single table inheritance, but translate rows to relational is a pain.

I'm using scala 2.10.3 + sbt 0.13.1

abstract class Pessoa2(val nome:String, val tipo:String)
case class PessoaFisica2(override val nome:String, val cpf:String) extends Pessoa2(nome,"F")
case class PessoaJuridica2(override val nome:String, val cnpj:String) extends Pessoa2(nome, "J")

class PessoaTable(tag: Tag) extends Table[Pessoa2](tag, "PESSOAS"){
//    def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
def nome = column[String]("nome")
def tipo = column[String]("tipo")
def cpf = column[String]("CPF", O.Nullable)
def cnpj = column[String]("CNPJ", O.Nullable)

def * = (nome, tipo, cpf.?, cnpj.?) <> ({
      case (nome:String,"F",cpf:Option[String],_) => new PessoaFisica2(nome, cpf.get):Pessoa2
      case (nome:String,"J",_,cnpj:Option[String]) => new PessoaJuridica2(nome, cnpj.get):Pessoa2
    },{
    case PessoaFisica2(nome, Some(cpf)) => Some((nome, "F", cpf, ""))
    case PessoaJuridica2(nome, Some(cnpj)) => Some((nome, "J", "", cnpj))
  })
}

This ends with the error:

The argument types of an anonymous function must be fully known. (SLS 8.5) [error] Expected type was: ? => ?

[error] def * = (nome, tipo, cpf.?, cnpj.?) <> ({

[error] ^

[error] /Users/giovanni/Projetos/atende/clientes/app/model/Pessoas.scala:158: type mismatch;

[error] found : Any

[error] required: String

[error] case (nome,"F",cpf,_) => new PessoaFisica2(nome, cpf):Pessoa2

[error] ^

[error] /Users/giovanni/Projetos/atende/clientes/app/model/Pessoas.scala:158: type mismatch;

[error] found : Any

[error] required: String

[error] case (nome,"F",cpf,_) => new PessoaFisica2(nome, cpf):Pessoa2

[error] ^

[error] /Users/giovanni/Projetos/atende/clientes/app/model/Pessoas.scala:159: type mismatch;

[error] found : Any

[error] required: String

[error] case (nome,"J",_,cnpj) => new PessoaJuridica2(nome, cnpj):Pessoa2

[error] ^

[error] /Users/giovanni/Projetos/atende/clientes/app/model/Pessoas.scala:159: type mismatch;

[error] found : Any

[error] required: String

[error] case (nome,"J",_,cnpj) => new PessoaJuridica2(nome, cnpj):Pessoa2

[error] ^

[error] /Users/giovanni/Projetos/atende/clientes/app/model/Pessoas.scala:160: missing parameter type for expanded function

[error] The argument types of an anonymous function must be fully known. (SLS 8.5)

[error] Expected type was: ? => Option[?]

[error] },{

[error] ^

[error] /Users/giovanni/Projetos/atende/clientes/app/model/Pessoas.scala:157: No matching Shape found.

[error] Slick does not know how to map the given types.

[error] Possible causes: T in Table[T] does not match your * projection. Or you use an unsupported type in a Query (e.g. scala List).

[error] Required level: scala.slick.lifted.ShapeLevel.Flat

[error] Source type: (scala.slick.lifted.Column[String], scala.slick.lifted.Column[String], scala.slick.lifted.Column[Option[String]], scala.slick.lifted.Column[Option[String]])

[error] Unpacked type: (String, String, String, String)

[error] Packed type: Any

[error] def * = (nome, tipo, cpf.?, cnpj.?) <> ({

[error] ^

[error] 7 errors found

1
I almost using Hibernate, assuming all the costs of doing that, or finding alternatives.Giovanni Silva

1 Answers

6
votes

Try that:

abstract class Pessoa2(val nome:String, val tipo:String)
case class PessoaFisica2(override val nome:String, val cpf:String) extends Pessoa2(nome,"F")
case class PessoaJuridica2(override val nome:String, val cnpj:String) extends Pessoa2(nome, "J")


class PessoaTable(tag: Tag) extends Table[Pessoa2](tag, "PESSOAS"){
//    def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
def nome = column[String]("nome")
def tipo = column[String]("tipo")
def cpf = column[String]("CPF", O.Nullable)
def cnpj = column[String]("CNPJ", O.Nullable)

def * = (nome, tipo, cpf.?, cnpj.?) <> ({ t : (String, String, Option[String], Option[String])=> t match{
    case (nome:String,"F",cpf:Option[String],_) => new PessoaFisica2(nome, cpf.get):Pessoa2
    case (nome:String,"J",_,cnpj:Option[String]) => new PessoaJuridica2(nome, cnpj.get):Pessoa2
  }},{ k: Pessoa2 => k match{
    case PessoaFisica2(nome, cpf) => Some((nome, "F", Some(cpf), Some(""))): Option[(String, String, Option[String], Option[String])]
    case PessoaJuridica2(nome, cnpj) => Some((nome, "J", Some(""), Some(cnpj))): Option[(String, String, Option[String], Option[String])]
  }})
}

It should compile that way