branch14log

Versioning & Migrating Local Storage (in CoffeeScript)

04 Jan 2013

With the recent influx of applications with offline capabilities a recurring requirement is the versioning (in some cases even migration) of data stored in local storage. Especially during development it comes handy to be able to wipe the content of the local storage just by increasing a version number. In later stages of the project you might even face the problem to migrate the user's data to work with the new release. Here is some CoffeeScript code to inspire or steal from:
class Migrator

  # increase this version number to trigger migrations
  # and add an entry with the same key to @migration
  # with the function to be triggered
  version: 0

  constructor: ->
    super
    fingerprint = @fingerprint()
    @migrate fingerprint.version, @version

  # migrates from a given version to a given version
  # if the to-version is higher than the from-version
  migrate: (from, to) ->
    return unless to > from
    for i in [ (from+1)..to ]
      if migration = @migration[i]
        migration()
    json = JSON.stringify(@fingerprint(to))
    localStorage.setItem 'fingerprint', json

  # if version is given returns a new fingerprint with
  # given version and current timestamp
  #
  # if no version is given, tries to fetch the fingerprint
  # from localStorage and falls back to a new fingerprint
  # with version 0
  #
  # the timestamp is just there for your convenience, to
  # keep track of when last migration took place
  fingerprint: (version) ->
    return { version: version , timestamp: new Date() } if version?
    json = localStorage.getItem('fingerprint')
    return JSON.parse(json) if json?
    { version: 0, timestamp: new Date() }

  # migrations is a hash with version to migrate to as key
  # so if you set @version from 0 to 3, migration 1, 2 and 3
  # will be executed in that order if they exist
  migration:
    # dummy implementation of migration from version -1 to 0
    # as you can see it'll just clear the local storage, which
    # might very well NOT be what you want for other migrations
    0: -> localStorage.clear()