Skip to content

Instantly share code, notes, and snippets.

@tgpfeiffer
Created January 23, 2013 17:12
Show Gist options
  • Save tgpfeiffer/4610213 to your computer and use it in GitHub Desktop.
Save tgpfeiffer/4610213 to your computer and use it in GitHub Desktop.
How to add generic versioning to Lift's MongoDB classes.
/**
* Carries some page content.
*/
class Content extends MongoRecord[Content]
with ObjectIdPk[Content]
with Versioned[Content, ContentRevision] {
def meta = Content
def revisionMeta = ContentRevision
// ...
}
/**
* Stores revisions of the Content class.
*/
class ContentRevision
extends Revision[Content, ContentRevision]
with MongoRecord[ContentRevision]
with ObjectIdPk[ContentRevision] {
override def meta = ContentRevision
override def versionedMeta = Content
}
object ContentRevision
extends ContentRevision
with MongoMetaRecord[ContentRevision] {}
/**
* Represents a revision of a certain versioned class (e.g., a ContentRevision).
* Thanks to Tim Nelson for help with the Manifest parameter.
*/
abstract class Revision[T <: MongoRecord[T], TREV <: MongoRecord[TREV]](implicit mf: Manifest[T]) {
self: MongoRecord[TREV] =>
def versionedMeta: T with MongoMetaRecord[T]
/** The object that this is a revision of */
object of extends ObjectIdRefField(this.asInstanceOf[TREV], versionedMeta)
/** The date when the revision was created */
object created extends DateField(this.asInstanceOf[TREV]) {
override def defaultValue = new Date()
}
/** The actual data of the archived object */
object data extends BsonRecordField[TREV, T](this.asInstanceOf[TREV], versionedMeta)
}
/**
* This is needed so that we can call super.save() from Versioned.
*/
trait PreVersioned[T <: MongoRecord[T], TREV <: MongoRecord[TREV] with ObjectIdPk[TREV] with Revision[T, TREV]] {
def save: T
}
/**
* Represents a class that is versioned, i.e., has revisions.
*/
trait Versioned[T <: MongoRecord[T], TREV <: MongoRecord[TREV] with ObjectIdPk[TREV] with Revision[T, TREV]]
extends PreVersioned[T, TREV]
with Loggable {
self: MongoRecord[T] with ObjectIdPk[T] =>
/**
* To be overridden: points to the meta object of the class that we
* want to have versioned.
*/
def revisionMeta: TREV with MongoMetaRecord[TREV]
/**
* Store a version of this object in the history before save.
*/
abstract override def save = {
logger.debug("before saving " + id.is)
meta.find(id.is).foreach(obj => {
tryo {
val hist = revisionMeta.createRecord.of(id.is).data(obj).asInstanceOf[TREV].save
hist
} match {
case Failure(msg, _, _) =>
logger.error("error while creating history item for " + id.is + ": " + msg)
case _ =>
logger.info("created history item for " + id.is)
}
})
super.save
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment