Question

I would like to find a simple way to access the maximum value of a Mapped element in liftweb, here is an example of what I actually do:

Mapper part

class MappedEntity extends LongKeyedMapper[MappedEntity] with IdPK {
  def getSingleton = MappedEntity
  object targetRaw extends MappedInt(this)
}

object MappedEntity extends MappedEntity with LongKeyedMetaMapper[MappedEntity]

Search part

val max = MappedEntity.findAllByInsecureSql(
  "SELECT MAX (targetRaw) AS targetRaw FROM MappedEntity", 
  IHaveValidatedThisSQL("chris", "2011,11,14")
  ).head.targetRaw.get

When supposing that I work with the SQL table called MappedEntity, I want max to contain either a string or an int equal to the maximum value contained in targetRaw

If you have any suggestion or any question I will be happy to help.

Was it helpful?

Solution

I don't believe that lift-mapper has a built-in way of running this query. In fact, it's very short on any sort of aggregate functions. All I see are some count methods.

The find* methods are only suitable for returning objects of the Mappers type, as you can see by their return types.

Given that there's no great way to do this in Lift as it stands, you have several options to choose from.

  1. Use lift-squeryl-record instead of lift-mapper. Squeryl is a more complete ORM, and supports group and aggregate functions.

  2. Create your own trait which adds max functions to a MetaMapper. This would be a bit of work, but you can use the implementation of count as a guide.

    • Technically, there could be a more general implementation that handles all of the aggregate functions (max, min, sum, count, ...). That may be what we in the business call 'overkill'.
  3. Just write some SQL. Lift offers a loan-pattern way of obtaining a connection to the database. It also has loan-pattern helpers for preparing statements and executing queries in such a was that everything is automagically closed when you're done with it.

    DB.use(DefaultConnectionIdentifier) { conn =>
      // execute query
    }
    
  4. Find the object with the value your looking for, then just retrieve that field. This has the distinct disadvantage of being ugly, slow and brittle.

    val max: Option[String] = MappedEntity.findAll(
      BySql("targetRaw IN (SELECT MAX (targetRaw) FROM MappedEntity)",
        IHaveValidatedThisSQL("chris", "2011,11,14")).map(_.targetRaw.is).headOption
    

OTHER TIPS

Here is the solution I finally used:

val max = DB.runQuery("SELECT YEAR(MAX(targetRaw)) FROM targetTable")._2.head.head.toInt
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top