My use case (wrt
https://github.com/lift/framework/issues/1259)
requires two things:
1) having centralized equality check for new value (when the field
is being set). This requires having setBox overridden like this:
trait FieldExtensions[T] extends TypedField[T] { ....
def assignment: org.squeryl.dsl.ast.UpdateAssignment
var dirty__? = false // second dirty value that I control, your
fix to have the original one being left untouched while populated
will make possible to get rid of this one.
override def setBox(in: Box[T]): Box[T] = {
val data =
FieldExtensions.dataField.invoke(this).asInstanceOf[Box[T]]
if (!data.isEmpty && data != in) dirty__? = true
super.setBox(in)
}
}
Without direct (or via getter) access I cannot reliably check for
comparison since accessors like get/is return "value" method which
in turn is "def value: MyType = valueBox openOr defaultValue".
2) being able to abstract over === for id/idField for MetaRecord so
I can:
trait SquerylMetaRecord[K, BaseRecord <: Record[BaseRecord] with
KeyedEntity[K]] extends MetaRecord[BaseRecord] {
self: BaseRecord =>
type KeyType = K
def table: Table[BaseRecord]
def collectionName =
table.name // abstracted to my own
MetaRecord so CRUD is not squeryl specific (can be reused for
Mongo-Record, etc)
......
def updatePartial(record: BaseRecord) {
def assign(rec: BaseRecord): Seq[dsl.ast.UpdateAssignment] =
rec.fields.collect{case f: FieldExtensions[_] if f.dirty__? =>
f}.map(_.assignment) // as "dirty" marker trait for now
inTransaction{
// here, although I have all the set assignments in
place, I also need "find by id" (I have no idea what constraints
should I put here on K to have reasonably typed def ===, I thought
about unused now trait KeyField from record)
table.update(r => where(
r.id ===
record.id)
set(assign(a): _*)
// full update via table.update(o: T)(implicit ev: T
<:< KeyedEntity[_]) makes no trouble here since it's delegated
to squeryl which doesn't use sql-dsl for it
}
}
}
To show the whole picture, here is abstracted crudify that doesn't
know about squeryl:
import net.liftweb._
import record.{Field}
import common.{Box, Empty, Full}
import scala.xml.NodeSeq
trait RecordCrudify[BaseRecord <: Record[BaseRecord]] extends
BaseCrudify {
self: MetaRecord[BaseRecord] =>
type TheCrudType = BaseRecord
type FieldPointerType = Field[_, TheCrudType]
override def calcPrefix = collectionName :: Nil
override def fieldsForDisplay: List[FieldPointerType] =
metaFields.filter(_.shouldDisplay_?)
override def computeFieldFromPointer(instance: TheCrudType,
pointer: FieldPointerType): Box[FieldPointerType] =
instance.fieldByName(
pointer.name)
override def create = createRecord
// bridge replacements, the brigdes are not needed after all
override def buildBridge(in: TheCrudType): CrudBridge =
sys.error("buildBridge is turned off")
override def buildFieldBridge(from: FieldPointerType):
FieldPointerBridge = sys.error("buildFieldBridge is turned off")
override def crudValidate(in: TheCrudType) = in.validate
override def crudDisplayHtml(in: FieldPointerType): NodeSeq =
in.displayHtml
override def findForParam(in: String): Box[BaseRecord] =
findByString(in)
override def findForList(start: Long, count: Int) =
findRange(start, count)
// bridge replacements
protected override def crudSave(in: BaseRecord) = save(in)
protected override def crudDelete(in: BaseRecord) = delete(in)
override def obscurePrimaryKey(in: BaseRecord): String =
idToString(in)
}
a MetaRecord that doesn't know about crud:
import net.liftweb.record.{MetaRecord => OMetaRecord}
import net.liftweb.common.Box
trait MetaRecord[BaseRecord <: Record[BaseRecord]] extends
OMetaRecord[BaseRecord] {
self: BaseRecord =>
type KeyType
def collectionName: String
def idFromString(in: String): KeyType // (implicit provider:
IdProvider[KeyType]) = provider.idFromString(in)//
def idToString(in: BaseRecord): String
def findByString(in: String): Box[BaseRecord]
def findRange(start: Long, count: Int): List[BaseRecord]
def save(record: BaseRecord): Boolean
def delete(record: BaseRecord): Boolean
}
and SquerylMetaRecord:
trait SquerylMetaRecord[K, BaseRecord <: Record[BaseRecord] with
KeyedEntity[K]] extends MetaRecord[BaseRecord] {
self: BaseRecord =>
type KeyType = K
def table: Table[BaseRecord]
def collectionName =
table.name
def idToString(in: BaseRecord) = in.id.toString
def findByString(in: String) = inTransaction {
table.lookup(idFromString(in))
}
def findRange(start: Long, count: Int) = inTransaction {
query(t => select(t)).page(start.toInt, count).toList
}
def save(record: BaseRecord) = {
if (record.isPersisted) {
inTransaction{table.update(record)} // I don't want to
perform full update here
} else {
inTransaction{table.insert(record)}
}
true
}
def delete(record: BaseRecord) = table.delete(
record.id)
def query[R](f: BaseRecord => dsl.QueryYield[R]): Query[R] =
from(table)(f)
}
Thanks,
W dniu 2012-04-16 17:58, David Whittaker pisze: