New Mapped Fields (MappedTimestamp and MappedMac)

9 views
Skip to first unread message

Peter Robinett

unread,
Jul 30, 2009, 8:53:58 PM7/30/09
to Lift
Hi all,

As some of you may have noticed, I have been playing around with
timestamps[1] and mac addresses[2] in my models. I really like
Mapper's specialized fields, both to make it easier for people to read
model definitions and to better ensure that only valid values are used
along all levels of the service, from the persistence to the
presentation layers.

So, I would like to propose an effort to develop more specialized
fields, starting with MappedTimestamp and MappedMac. I talked to David
today and he is willing to provide some advice. Hopefully this will
prove a useful way for me to improve my Scala knowledge and contribute
to Lift.

Focusing just on the two mapped fields I mentioned, do you have any
comments how that should be implemented? My thinking is that
MappedTimestamp would be stored as a java.util.date and MappedMac as
a String, converting both of them to Longs for the database in the
interest of saving space.

Are there any other mapped fields you'd like to see? I'll add that I
think using the units compiler plugin[3] looks cool[4] but probably
would be considered to create an unacceptable dependency.

Peter Robinett

[1]: http://groups.google.com/group/liftweb/browse_thread/thread/b4bdedfb7c935917
[2]: http://groups.google.com/group/liftweb/browse_thread/thread/41650fc1eb0098bd
[3]: https://lampsvn.epfl.ch/trac/scala/browser/compiler-plugins/units/trunk
[4]: http://www.michaelnygard.com/blog/2009/05/units_of_measure_in_scala.html

Nolan Darilek

unread,
Jul 30, 2009, 9:49:00 PM7/30/09
to lif...@googlegroups.com
On 07/30/2009 07:53 PM, Peter Robinett wrote:
> Are there any other mapped fields you'd like to see?

I'll be needing a MappedMap in one of my upcoming projects, basically a
way of associating keyword/value pairs with my models. I'd really rather
avoid the extra overhead of creating models and associations for these
pairs, especially since they are never needed outside of the model
itself. In the older Merb incarnation of this project, I just dumped the
data to JSON and stored it in a text field on the object, kinda a poor
man's document database if you will. :)

g-man

unread,
Jul 30, 2009, 9:56:21 PM7/30/09
to Lift
I've been working on implementing a better Date solution in my apps,
and the best one I have found is to use a Long to store the instant in
millis, then pass that down the line in response, let JavaScript do
all the conversions to display and validations for submission client-
side, and then send back millis in a request.

It's just an world-wide instant in time, after all, with no time zone
(UTC), and I can do all my date math easily with millis.

True, it's not human-readable in the database, but so what? True,
relying on JS may not be a universal solution, but how many users
don't have JavaScript turned on?

This approach would fit in well with your idea, being a Long, but I
see no need to bring in the Date object at all. Even if you want to
let the Java Date do any work, it can still use the millis perfectly,
and mySQL strips off the milli-portion of its timestamp data type
anyway, which is why it's useless.

Walks like a Date, talks like a Date, but it's a milli...


On Jul 30, 5:53 pm, Peter Robinett <pe...@bubblefoundry.com> wrote:
> Hi all,
>
> As some of you may have noticed, I have been playing around with
> timestamps[1] and mac addresses[2] in my models. I really like
> Mapper's specialized fields, both to make it easier for people to read
> model definitions and to better ensure that only valid values are used
> along all levels of the service, from the persistence to the
> presentation layers.
>
> So, I would like to propose an effort to develop more specialized
> fields, starting with MappedTimestamp and MappedMac. I talked to David
> today and he is willing to provide some advice. Hopefully this will
> prove a useful way for me to improve my Scala knowledge and contribute
> to Lift.
>
> Focusing just on the two mapped fields I mentioned, do you have any
> comments how that should be implemented? My thinking is that
> MappedTimestamp would be stored as a java.util.date and MappedMac as
> a  String, converting both of them to Longs for the database in the
> interest of saving space.
>
> Are there any other mapped fields you'd like to see? I'll add that I
> think using the units compiler plugin[3] looks cool[4] but probably
> would be considered to create an unacceptable dependency.
>
> Peter Robinett
>
> [1]:http://groups.google.com/group/liftweb/browse_thread/thread/b4bdedfb7...
> [2]:http://groups.google.com/group/liftweb/browse_thread/thread/41650fc1e...

Naftoli Gugenheim

unread,
Jul 31, 2009, 12:31:15 AM7/31/09
to pe...@bubblefoundry.com, lif...@googlegroups.com
Maybe I'm missing something that was said, but why can't MappedTimestamp extend MappedDate(Time)? Or better yet, provide a trait to mix in with either of the above?

-------------------------------------
Peter Robinett<pe...@bubblefoundry.com> wrote:


Hi all,

As some of you may have noticed, I have been playing around with
timestamps[1] and mac addresses[2] in my models. I really like
Mapper's specialized fields, both to make it easier for people to read
model definitions and to better ensure that only valid values are used
along all levels of the service, from the persistence to the
presentation layers.

So, I would like to propose an effort to develop more specialized
fields, starting with MappedTimestamp and MappedMac. I talked to David
today and he is willing to provide some advice. Hopefully this will
prove a useful way for me to improve my Scala knowledge and contribute
to Lift.

Focusing just on the two mapped fields I mentioned, do you have any
comments how that should be implemented? My thinking is that
MappedTimestamp would be stored as a java.util.date and MappedMac as
a String, converting both of them to Longs for the database in the
interest of saving space.

Are there any other mapped fields you'd like to see? I'll add that I
think using the units compiler plugin[3] looks cool[4] but probably
would be considered to create an unacceptable dependency.

Peter Robinett

[1]: http://groups.google.com/group/liftweb/browse_thread/thread/b4bdedfb7c935917
[2]: http://groups.google.com/group/liftweb/browse_thread/thread/41650fc1eb0098bd

Peter Robinett

unread,
Aug 3, 2009, 9:44:40 PM8/3/09
to Lift
Nolan, I like the idea, especially using JSON as the serialization
format. Do you have any code you could share?

Peter

Peter Robinett

unread,
Aug 3, 2009, 9:56:39 PM8/3/09
to Lift
Naftoli, that's a great suggestion. I've taken a first, very bad stab
at such a trait:
http://github.com/pr1001/lift_1_1_sample/blob/ab945ba4960e6fc32c8f04c72010332973a08bd6/src/main/scala/com/liftcode/model/MappedTimestamp.scala.

As the commit message says, the code is horrible and doesn't compile
because my Scala knowledge is quite limited. I'd appreciate advice on
how to correct my copy-and-paste job.

Peter
> [1]:http://groups.google.com/group/liftweb/browse_thread/thread/b4bdedfb7...
> [2]:http://groups.google.com/group/liftweb/browse_thread/thread/41650fc1e...

Naftoli Gugenheim

unread,
Aug 3, 2009, 9:59:43 PM8/3/09
to lif...@googlegroups.com
Do you mind pasting it to the list?

Peter Robinett

unread,
Aug 4, 2009, 3:51:58 AM8/4/09
to Lift
Not at all, I just thought it would be hard to read. Here it is:

Peter

import _root_.java.sql.{ResultSet, Types}
import _root_.java.util.Date
import _root_.java.lang.reflect.Method

import _root_.net.liftweb._
import util._
import Helpers._
import http._
import S._
import js._

import _root_.scala.xml.{NodeSeq}

import net.liftweb.mapper.Mapper
import net.liftweb.mapper.MappedDateTime

trait MappedTimestamp[T<:Mapper[T]] extends MappedDateTime[Date] {
this: T with MappedTimestamp[T] =>

override def toLong: Long = is match {
case null => 0L
case d: Date => d.getTime
}

/**
* Get the JDBC SQL Type for this field
*/
override def targetSQLType = Types.BIGINT

/**
* Create an input field for the item
*/
override def _toForm: Box[NodeSeq] =
S.fmapFunc({s: List[String] => this.setFromAny(s)}){funcName =>
Full(<input type='text' id={fieldId}
name={funcName} lift:gc={funcName}
value={is match {case null => "" case s => s}}/>)
}

override def jdbcFriendly(field : String) : Object = is match {
case null => null
case d => new _root_.java.sql.Date(d.getTime)
}

override def real_convertToJDBCFriendly(value: Date): Object = if
(value == null) null else new _root_.java.lang.Long(value.getTime)

override def buildSetActualValue(accessor: Method, v: AnyRef,
columnName: String): (T, AnyRef) => Unit =
(inst, v) => doField(inst, accessor, {case f: MappedTimestamp[T] =>
f.st(toDate(v))})

override def buildSetLongValue(accessor: Method, columnName:
String): (T, Long, Boolean) => Unit =
(inst, v, isNull) => doField(inst, accessor, {case f: MappedTimestamp
[T] => f.st(if (isNull) Empty else Full(new Date(v)))})

override def buildSetStringValue(accessor: Method, columnName:
String): (T, String) => Unit =
(inst, v) => doField(inst, accessor, {case f: MappedTimestamp[T] =>
f.st(toDate(v))})

override def buildSetDateValue(accessor: Method, columnName:
String): (T, Date) => Unit =
(inst, v) => doField(inst, accessor, {case f: MappedTimestamp[T] =>
f.st(Full(v))})

override def buildSetBooleanValue(accessor: Method, columnName:
String): (T, Boolean, Boolean) => Unit =
(inst, v, isNull) => doField(inst, accessor, {case f: MappedTimestamp
[T] => f.st(Empty)})

/**
* Given the driver type, return the string required to create the
column in the database
*/
override def fieldCreatorString(dbType: DriverType, colName:
String): String = colName + " " + dbType.longColumnType
}


On Aug 3, 6:59 pm, Naftoli Gugenheim <naftoli...@gmail.com> wrote:
> Do you mind pasting it to the list?
>
> -------------------------------------
>
> Peter Robinett<pe...@bubblefoundry.com> wrote:
>
> Naftoli, that's a great suggestion. I've taken a first, very bad stab
> at such a trait:http://github.com/pr1001/lift_1_1_sample/blob/ab945ba4960e6fc32c8f04c....

Naftoli Gugenheim

unread,
Aug 4, 2009, 4:17:42 PM8/4/09
to pe...@bubblefoundry.com, lif...@googlegroups.com
Didn't look very closely, but if you extend MappedDate you lock yourself out of MappedDatTime and vice versa. However both of them extend MappedField[Date, T] which is a trait not a class, so if you extend that it should be mixable in to both.
What was the compile error?
Aren't you writing a lot of functionality that is in MappedDate(Time)? Define your mixin as a delta to MappedDate(Time); it should only have the aspects that differentiate it.

Peter Robinett

unread,
Aug 4, 2009, 5:27:27 PM8/4/09
to Lift
Ahh, good idea. The compile errors all had to do with the the type
parameters. I don't know much about Scala's type system yet, so I was
defining the trait incorrectly based upon code I had copied and
pasted.

I'm now trying to have MappedTimestamp extend MappedField[Date, T]
instead and I am this much closer to getting it to work. Here are the
compile errors:
/Users/peter/Sites/liftstringprimary/src/main/scala/com/liftcode/model/
Cat.scala:38: error: illegal inheritance;
object ts inherits different type instances of trait MappedField:
net.liftweb.mapper.MappedField
[java.util.Date,net.liftweb.mapper.MappedDateTime[java.util.Date]] and
net.liftweb.mapper.MappedField[java.util.Date,com.liftcode.model.Cat]
object ts extends MappedDateTime(this) with MappedTimestamp
[MappedDateTime[Date]]
^
/Users/peter/Sites/liftstringprimary/src/main/scala/com/liftcode/model/
Cat.scala:38: error: type arguments [net.liftweb.mapper.MappedDateTime
[java.util.Date]] do not conform to trait MappedTimestamp's type
parameter bounds [T <: net.liftweb.mapper.Mapper[T]]
object ts extends MappedDateTime(this) with MappedTimestamp
[MappedDateTime[Date]]
^
two errors found

The relevant lines, I believe, are:
Cat.scala: object ts extends MappedDateTime(this) with MappedTimestamp
[MappedDateTime[Date]]
MappedTimstamp.scala: trait MappedTimestamp[T<:Mapper[T]] extends
MappedField[Date, T] {

And the code on GitHub:
http://github.com/pr1001/lift_1_1_sample/tree/master

As for all the overrides, looking at it again I see that I didn't need
to override all those build methods. The others are still needed to
have millisecond Longs where appropriate.

Peter

Peter

Peter Robinett

unread,
Aug 7, 2009, 1:47:48 PM8/7/09
to Lift
Just to give this thread a little bump, could someone give me some
tips on what's wrong with the types of the MappedTimestamp trait?

Thanks,
Peter

David Pollak

unread,
Aug 7, 2009, 8:19:51 PM8/7/09
to lif...@googlegroups.com
Why are you trying to make this a mixin?  Why not just create a MappedTimestamp field?
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

Peter Robinett

unread,
Aug 8, 2009, 5:05:01 AM8/8/09
to Lift
I thought Naftoli's suggestion to make it a mixin so that it could be
added to MappedDates or MappedDateTimes was a reasonable one. Do you
think this just complicates things?

Peter
> Beginning Scalahttp://www.apress.com/book/view/1430219890

David Pollak

unread,
Aug 8, 2009, 9:30:10 AM8/8/09
to lif...@googlegroups.com
On Sat, Aug 8, 2009 at 2:05 AM, Peter Robinett <pe...@bubblefoundry.com> wrote:

I thought Naftoli's suggestion to make it a mixin so that it could be
added to MappedDates or MappedDateTimes was a reasonable one. Do you
think this just complicates things?

Yes.  It's more code for a developer to type and it's more complex under the covers.



--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890

Naftoli Gugenheim

unread,
Aug 8, 2009, 11:23:03 PM8/8/09
to lif...@googlegroups.com
The truth is, is it really useful to have a timestamp that excludes the time of day?

Peter Robinett

unread,
Aug 12, 2009, 2:53:27 PM8/12/09
to Lift
Ok, I think we all agree now that a mixin trait wasn't the best idea.
I've gone back and rewritten MappedTimestamp as a class which extended
MappedDateTime, and I think it's now working correctly. The commit is
here: http://github.com/pr1001/lift_1_1_sample/commit/d744a7cffe7d929ddbc531e8d8afea864a6fdc72

Peter
Reply all
Reply to author
Forward
0 new messages