Skip to content

Instantly share code, notes, and snippets.

@iron9light
Created September 6, 2011 18:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iron9light/1198513 to your computer and use it in GitHub Desktop.
Save iron9light/1198513 to your computer and use it in GitHub Desktop.
Tag helper for squeryl
package iron9light.lessTM.business.lib
import scala.collection.mutable.Map
import org.squeryl.PrimitiveTypeMode._
import org.squeryl.{Schema, Table, KeyedEntity}
import org.squeryl.dsl.ast.{EqualityExpression, TypedExpressionNode}
import org.squeryl.dsl.{OneToManyRelation, ManyToOne, OneToMany, CompositeKey3}
import java.sql.Timestamp
import java.util.{UUID, Date}
/**
* @author il
* @version 9/5/11 6:39 PM
*/
abstract class Taggable[K, T <: Taggable[K, T]: Manifest] extends KeyedEntity[K] {self: T =>
lazy val tags = TagModel.tags[K, T](this)
}
trait TagEntity[K] extends KeyedEntity[CompositeKey3[K, String, Option[String]]] {
def itemId: K
def tag: String
def tagType: Option[String]
def id = compositeKey(itemId, tag, tagType)
def tagId = compositeKey(tag, tagType)
// todo: implicit convertTo(tagId: CompositeKey2[String, Option[String]]): TagInfo
}
trait TagModel extends Schema {
def taggable[K, T <: Taggable[K, T]](implicit convert: K => TypedExpressionNode[_], manifestT: Manifest[T], manifestTag: Manifest[K]): Table[T] = taggable[K, T](tableNameFromClass(manifestT.erasure))
def taggable[K, T <: Taggable[K, T]](name: String)(implicit convert: K => TypedExpressionNode[_], manifestT: Manifest[T], manifestTag: Manifest[K]): Table[T] = taggable[K, T](name, None)
def taggable[K, T <: Taggable[K, T]](name: String, prefix: String)(implicit convert: K => TypedExpressionNode[_], manifestT: Manifest[T], manifestTag: Manifest[K]): Table[T] = taggable[K, T](name, Some(prefix))
def taggable[K, T <: Taggable[K, T]](name: String, prefix: Option[String])(implicit convert: K => TypedExpressionNode[_], manifestT: Manifest[T], manifestTag: Manifest[K]): Table[T] = {
// case class TagInfo(itemId: K, tag: String, tagType: Option[String] = None) extends TagEntity[K]
val (t, tTags) = prefix.map(x => (table[T](name, x), table(name + "Tag", x)(TagModel.tagManifest[K]).asInstanceOf[Table[TagEntity[K]]])).getOrElse(table[T](name), table(name + "Tag")(TagModel.tagManifest[K]).asInstanceOf[Table[TagEntity[K]]])
// val tTags = table[TagInfo](name + "Tag", prefix)
on(tTags) {
tag => declare(
tag.tagId is (unique, indexed)
)
}
val tToTags = oneToManyRelation(t, tTags).via((item, tag) => new EqualityExpression(convert(item.id), convert(tag.itemId)))
TagModel.addTagTables[K, T](t, tTags, tToTags)
t
}
}
object TagModel {
private val map = Map[Manifest[_], (Table[_], Table[_], OneToManyRelation[_, _])]()
def table[T <: Taggable[_, T]: Manifest] : Table[T] = map(manifest[T])._1.asInstanceOf[Table[T]]
def tags[K, T <: Taggable[K, T]: Manifest](item: T): OneToMany[_ <: TagEntity[K]] = map(manifest[T])._3.asInstanceOf[OneToManyRelation[T, _ <: TagEntity[K]]].left(item)
def item[T <: Taggable[_, T]: Manifest](tagInfo: TagEntity[_]): ManyToOne[T] = map(manifest[T])._3.asInstanceOf[OneToManyRelation[T, TagEntity[_]]].right(tagInfo)
private[lib] def addTagTables[K, T <: Taggable[K, T]](t: Table[T], tTags: Table[_ <: TagEntity[K]], tToTags: OneToManyRelation[T, _ <: TagEntity[K]])(implicit manifestT: Manifest[T]) {
map += manifest[T] -> (t, tTags, tToTags)
}
private[lib] def tagManifest[K](implicit m: Manifest[K]): Manifest[_] = m match {
case _ if m == manifest[Byte] => manifest[ByteTag]
case _ if m == manifest[Int] => manifest[IntTag]
case _ if m <:< manifest[String] => manifest[StringTag]
case _ if m == manifest[Double] => manifest[DoubleTag]
case _ if m <:< manifest[BigDecimal] => manifest[BigDecimalTag]
case _ if m == manifest[Float] => manifest[FloatTag]
case _ if m == manifest[Long] => manifest[LongTag]
case _ if m == manifest[Boolean] => manifest[BooleanTag]
case _ if m <:< manifest[Date] => manifest[DateTag]
case _ if m <:< manifest[Timestamp] => manifest[TimestampTag]
case _ if m <:< manifest[Enumeration#Value] => manifest[EnumTag]
case _ if m <:< manifest[UUID] => manifest[UUIDTag]
case _ if m <:< manifest[Array[Byte]] => manifest[BytesTag]
}
case class ByteTag(itemId: Byte, tag: String, tagType: Option[String] = None) extends TagEntity[Byte]
case class IntTag(itemId: Int, tag: String, tagType: Option[String] = None) extends TagEntity[Int]
case class StringTag(itemId: String, tag: String, tagType: Option[String] = None) extends TagEntity[String]
case class DoubleTag(itemId: Double, tag: String, tagType: Option[String] = None) extends TagEntity[Double]
case class BigDecimalTag(itemId: BigDecimal, tag: String, tagType: Option[String] = None) extends TagEntity[BigDecimal]
case class FloatTag(itemId: Float, tag: String, tagType: Option[String] = None) extends TagEntity[Float]
case class LongTag(itemId: Long, tag: String, tagType: Option[String] = None) extends TagEntity[Long]
case class BooleanTag(itemId: Boolean, tag: String, tagType: Option[String] = None) extends TagEntity[Boolean]
case class DateTag(itemId: Date, tag: String, tagType: Option[String] = None) extends TagEntity[Date]
case class TimestampTag(itemId: Timestamp, tag: String, tagType: Option[String] = None) extends TagEntity[Timestamp]
case class EnumTag(itemId: Enumeration#Value, tag: String, tagType: Option[String] = None) extends TagEntity[Enumeration#Value]
case class UUIDTag(itemId: UUID, tag: String, tagType: Option[String] = None) extends TagEntity[UUID]
case class BytesTag(itemId: Array[Byte], tag: String, tagType: Option[String] = None) extends TagEntity[Array[Byte]]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment