I have defined my model as follows:
object Curr extends Curr with LongKeyedMetaMapper[Curr] with CRUDify[Long, Curr] {
}
class Curr extends LongKeyedMapper[Curr] with IdPK with CreatedUpdated {
def getSingleton = Curr
object code extends MappedString(this, 100)
object name extends MappedString(this, 100)
}
object Country extends Country with LongKeyedMetaMapper[Country] with CRUDify[Long, Country] {
}
class Country extends LongKeyedMapper[Country] with IdPK with CreatedUpdated {
def getSingleton = Country
object name extends MappedString(this, 100)
object currid extends MappedLongForeignKey(this, Curr) {
override def asHtml = {
<span>{Curr.find(By(Curr.id, this)).map(c => (c.name + " " + c.code)).openOr(Text(""))}</span>
}
override def validSelectValues: Box[List[(Long, String)]] =
Full(Curr.findAll(OrderBy(Curr.name, Ascending)).map(c => (c.id.is, c.code.is)))
}
}
I will have many such models, and I want to remove the redundancy of defining asHtml
and validSelectValues
for the many models that will have foreign keys. I figured I could do this with a trait MyField
that would mix in to my model as follows:
object currid extends {val MyModel = Curr } MappedLongForeignKey(this, Curr) with MyField[Curr] {
with the trait being defined something like:
trait MyField[T <: LongKeyedMetaMapper[T] with IdPK] {
val MyModel: T
override def asHtml = {
<span>{MyModel.find(By(MyModel.id, this)).map(c => (c.name + " " + c.name)).openOr(Text(""))}</span>
}
override def validSelectValues: Box[List[(Long, String)]] =
Full(MyModel.findAll(OrderBy(MyModel.name, Ascending)).map(c => (c.id.is, c.name.is)))
}
My trait, as written above, does not work. Here is the error that the compiler generates:
No implicit view available from net.liftweb.mapper.MyField[T] => Long.
[error] <span>{MyModel.find(By(MyModel.id, this)).map(c => (c.name + " " + c.name)).openOr(Text(""))}</span>
[error] ^
value name is not a member of type parameter T
[error] Full(MyModel.findAll(OrderBy(MyModel.name, Ascending)).map(c => (c.id.is, c.name.is)))
[error] ^
I will make sure that each MyModel
will have a name
member. Can anyone advise on how to implement this trait?
Thanks!
I have found a solution. I created my own KeyedMapper, MetaMapper and MappedForeignKey. In the example MyData and MyForeignData are two database tables and MyData contains a foreign key to MyForeignData. CRUDify is included and in the browser you can see and edit the foreign key, displayed with the table column override def primaryKeyDisplayField = table_column_field
import scala.xml._
import net.liftweb.common._
import net.liftweb.mapper._
import net.liftweb.util._
trait MyMapper[OwnerType <: MyMapper[OwnerType]]
extends LongKeyedMapper[OwnerType] with IdPK {
self: OwnerType =>
}
trait MyMetaMapper[A <: MyMapper[A]]
extends LongKeyedMetaMapper[A]
with LongCRUDify[A] {
self: A =>
def primaryKeyDisplayField: BaseOwnedMappedField[A] = null
}
abstract class MyMappedForeignKey[T<:MyMapper[T], O<:MyMapper[O]](theOwner: T, _foreignMeta: => MyMetaMapper[O])
extends MappedLongForeignKey[T, O](theOwner, _foreignMeta) {
override def foreignMeta = _foreignMeta
override def dbIndexed_? = true
override def asHtml = {
<span>{foreignMeta.findByKey(this.get)
.map(_.fieldByName(foreignMeta.primaryKeyDisplayField.name).openOr(Text("Error"))).openOr(Text("ERROR MyMappedForeignKey"))}</span>
}
override def validSelectValues/*: Box[List[(Long, String)]]*/ = {
Full(foreignMeta.findAll(/*OrderBy(foreignMeta.primaryKeyField, Ascending)*/)
.map(i => (i.id.get,
i.fieldByName(foreignMeta.primaryKeyDisplayField.name).openOr(Text("ERROR")).toString())))
}
}
class MyData extends MyMapper[MyData] {
def getSingleton = MyData
object myForeignData extends MyMappedForeignKey(this, MyForeignData)
object name extends MappedString(this, 30)
}
object MyData extends MyData with MyMetaMapper[MyData] { }
class MyForeignData extends MyMapper[MyForeignData] {
def getSingleton = MyForeignData
object name extends MappedString(this, 30)
}
object MyForeignData extends MyForeignData with MyMetaMapper[MyForeignData] {
override def primaryKeyDisplayField = name
}