Skip to content

Creating a Custom Store in Tower

Lance Pollard edited this page Oct 17, 2012 · 4 revisions

To create a custom store in Tower, implement the following methods:

class Tower.MyCustomStore extends Tower.Store
  find: (cursor, callback) ->

  insert: (cursor, callback) ->

  update: (cursor, callback) ->

  destroy: (cursor, callback) ->

  count: (cursor, callback) ->

  exists: (cursor, callback) ->

  # setup the database
  @initialize: (callback) ->

  # completely clear the database
  @clean: (callback) ->

Implementing those methods will allow you to save models with simple fields. To support associations, you can implement before/after hooks for find/insert/update/destroy, or if you can do joins you may just be able to handle them without any hooks (mongodb needs to use hooks though, for example, to implement hasMany associations, while SQL can use joins).

class Tower.MyCustomStore extends Tower.Store
  # ...
  runBeforeInsert: (cursor, callback) ->

  runAfterInsert: (cursor, callback) ->

  runBeforeUpdate: (cursor, callback) ->

  runAfterUpdate: (cursor, callback) ->

  runBeforeDestroy: (cursor, callback) ->

  runAfterDestroy: (cursor, callback) ->

  runBeforeFind: (cursor, callback) ->

  runAfterFind: (cursor, callback, records) ->

The first argument to every method is a cursor, which contains all the information the database needs. You can call cursor.toParams() to get it in a compiled JSON object:

{
  "sort": [],
  "conditions": {

  },
  "page": 2
}

All that's necessary is to iterate through each item in the cursor's criteria, serialize it to whatever form it needs to be, then generate the database-specific query string/object, and make the database call.

The different field types to handle are:

boolean
integer
decimal (double)
long (double)
bigint
float
date
time
datetime
timestamp
string
text
binary
object == 'blob' == anything
hash
array
reference == id of related document
geo
bitmask == enumerable (array) that gets transformed into an integer for storage compression

Each database supports a subset of these field types, some more than others, so all that is required is, for each attribute passed into say the insert method (via the cursor), get the field type, and encode/decode it accordingly.

To get the field types, just grab the fields hash off the model the store instance is wrapping:

class Tower.MyCustomStore extends Tower.Store
  find: (cursor, callback) ->
    attributes  = @serializeAttributesForFind(cursor.data[0].toJSON())

  serializeAttributesForFind: (attributes) ->
    # grab fields to get `type`
    fields      = Tower.constant(@className).fields()

    for key, value of attributes
      field = fields[key]

      if field
        type = field.type
      else
        # help them out, trying to save data that wasn't
        # defined by a field
        type = _.kind(value) # _.kind is a neat little helper

      # serialize each value for your custom datastore
      switch type
        when 'array'
          attributes[key] = JSON.stringify(value)
        when 'null', 'undefined', 'NaN'
          delete attributes[key]

    attributes

Note: the cursor.data is going to be refactored eventually so that you know what you're getting. Right now in the insert method you'll either get a hash or a record (most likely a record), but in the others you could just get query criteria.

Clone this wiki locally