How would this be implemented in terms of database table structure?

-------------------------------------
Jeppe Nejsum Madsen<je...@ingolfs.dk> wrote:

On Thu, Jan 7, 2010 at 6:34 PM, David Pollak
<feeder.of.the.be...@gmail.com> wrote:
> Can you post some example code of your current thinking as a GitHub project
> and we can work on refining it and tuning Mapper/MetaMapper to suit your
> needs?

I realize the original mail wasn't that informative. What can I say, I
was in a hurry running out the door :-)

I've been implementing this with the current mapper code and before
creating GitHub projects etc let me try to explain the use case and we
can see if something needs to be changed in mapper.

I need to implement support for temporal database concepts
(http://en.wikipedia.org/wiki/Temporal_database). For know I don't
need full bi-temporal data, only valid-time. Lets assume the following
simple schema:

class Person extends LongKeyedMapper[Person] with IdPK {
  def getSingleton = Person
  object name extends MappedPoliteString(this, 20)
  object address extends MappedLongForeignKey(this,Address)
}
object Person extends Person with LongKeyedMetaMapper[Person]

class Address extends LongKeyedMapper[Address] with IdPK {
  def getSingleton = Address
  object street extends MappedPoliteString(this, 20)
}
object Address extends Address with LongKeyedMetaMapper[Address]

The challenge is now to be able to track the different addresses that
this person have had over time and be able to answer questions such
as: what's the current address? What was the address at 2009-12-31
etc.

Ideally, I would like to just change the line

 object address extends MappedLongForeignKey(this,Address)

to

 object address extends MappedTemporalObject(this,Address)

and then be able to say e.g.

person.address.set(addr, validInterval) // Add address that is valid
in the specified interval
person.address.set(addr) // Add address that is valid from current date
person.address.history // Get list of addresses
person.address.current // Get current address
etc

This is pretty close to a OneToMany scenario with the added complexity
of a validity interval on the "many" part. I've used the OneToMany
code as inspiration and made a solution that works (while not being as
non-intrusive as the above)

There are at least two things that needs to happen:

1) Add new fields to the Address object. We need validFrom/to dates,
and foreign key. So currently, I must change my Address class into
this:

class Address extends LongKeyedMapper[Address] with IdPK with
ValidTime[Long,Address] {
  def getSingleton = Address
  object person extends MappedLongForeignKey(this, Person)
  object street extends MappedPoliteString(this, 20)
}

where ValidTime is a trait containing the fields validFrom, validTo

2) Hook into the person object so that any changed addresses are saved

class Person extends TemporalMapper[Long,Person] with
LongKeyedMapper[Person] with IdPK {
  def getSingleton = Person

  object field extends MappedPoliteString(this, 20)
  object address extends MappedTemporalObject(Person,Address.person)
}

where TemporalMapper is a trait that overrides save/delete etc and
MappedTemporalObject handles the collection of addresses.

The above solution works and is not too cumbersome. To make the really
nice solution, a few changes are need to mapper:

1) Ability construct a persisted entity dynamically. I.e I have the
original Address class with no valid time fields or fk reference, but
need to persist "Address with ValidTime with ForeignKey". This, I
think, is the hard part :-)

2) The MappedTemporalObject needs to hook into the lifecycle events of
the owner. I think what is needed is just for the LifecycleCallbacks
to be extended with methods that can actually influence the lifecycle
(ie if a lifecycle callback "save" fails, the owner "save" should
fail)

Let me know if this makes it more clear. As I said I have this
working, so it's not high priority to get these changes, but they
might come in handy in other scenarios as well.....

/Jeppe
-- 
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


-- 
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


Reply via email to