/salat

Fast bi-directional Scala case class to MongoDB mapping library

Primary LanguageScalaOtherNOASSERTION

Salat

Salat in four minutes... or less

Salat is a bi-directional Scala case class serialization library that leverages MongoDB's DBObject (which uses BSON underneath) as its target format.

The Salat project focuses on speed and simplicity of serializing case classes to and from target formats.

Salat is not a fully-fledged ORM and does not attempt to match the flexibility, compability or functionality of an ORM that would let you define relationships between classes, provide a query language, or serialize/deserialize every collection type known to Java or Scala.

How to get Salat

Add these repos to your SBT or Maven project:

val novusRels = "repo.novus rels" at "http://repo.novus.com/releases/"
val novusSnaps = "repo.novus snaps" at "http://repo.novus.com/snapshots/"

The main dependency is salat-core.

Latest release

Salat 0.0.7 release is available for Scala 2.8.1.

val salat = "com.novus" % "salat-core" % "0.0.7"

Latest snapshot

Salat 0.0.8-SNAPSHOT is available for both Scala 2.8.1 and 2.9.0-1.

val salat = "com.novus" %% "salat-core" % "0.0.8-SNAPSHOT"

Goals

  1. Convert an instance of any Scala case class to a DBObject suitable for insertion into a MongoDB database.

  2. Given a DBObject (which may have come from MongoDB, or elsewhere), instantiate an instance of the corresponding case class.

  3. Achieve goals 1 and 2 without sacrificing performance. This rules out use of reflection.

  4. Achieve goals 1, 2, and 3 as functionally as possible.

What are you giving up?

In developing Salat, we have made a key decision to make these particular sacrifices and not look back.

No support for anything but case classes

Scala case classes have key features that Salat uses to improve and speed up object serialization, including:

  • A single accessible constructor. Can be retrieved either by reflecting on the class itself, or through generated companion object.

  • The productIterator method provided by the Product interface: a non-reflective way to retrieve programmatically values of the case class' data members.

  • Data members can have default values; information missing in DBObject instance during re-inflation can be subbed in using default args defined at compile time.

Requires ScalaSig

So the first big improvement Salat offers for serialization is in being able to use case classes as products to get a list of indexed fields and their default arguments.

Well begun, but only half done. The other half is getting as much type information about the case class as possible, and then keeping that information on tap instead of having to derive it over and over again.

With these two pieces in hand, fast, reliable serialization without having to resort to runtime reflection is easy.

So thank you to EFPL for their wonderfully undocumented ScalaSig, which Salat uses to memoize hi-fi type information about each field in the case class.

Details about pickled Scala sigs are thin on the ground. Here's where we got started:

Java support has been ruled out

Requiring Product and a single constructor rules out using anything but a case class. Technically, in the distant future, we may be able to flex on the case class requirement enough to only require something very, very case class like.

However, Salat will never support classes defined in pure Java because they do not supply the requisite pickled Scala sig.

You can't freestyle in the REPL either

NB: it turns out that ScalaSig is incapable of "parsing" classes defined in the REPL. See SI-4567 for the gory details.

None of this code will work with classes that have no corresponding .class file or ScalaSig annotation.

Our ticket has been accepted as an improvement, but until this is fixed, if you want to experiment with serialization in the REPL:

  • define your model classes
  • run sbt console

Flexibility can wait

Salat is and will always be primarily focused on serializing and deserializing what's in the case class constructor.

There are some annotations that can be used to customize serialization at the case class level:

  • Support for typing concrete case class instances to a trait or abstract superclass using @Salat
  • Use @Key to change a key name
  • Use @Persist to persist a value not in case class constructor
  • Use @Ignore to ignore a field in the case class constructor (requires default value)
  • Use @EnumAs to choose whether to handle enums by id or by value

In addition, you can customize your persistence context with regards to:

  • type hinting strategy
  • type hinting key name
  • global key overrides
  • global enum handling strategy
  • default math context for BigDecimals

However, a lot of Salat's internal workings are not easily exposed or overriden right now. We are working to make Salat a more general-use serialization tool with future releases.

What's up with the name?

"Salat" is a transliteration of the Russian word "салат", for "salad".

Salat is light and doesn't slow you down through use of runtime reflection.