-
Notifications
You must be signed in to change notification settings - Fork 120
Creating a Custom Store in Tower
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:
``` coffeescript
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 theinsert
method you'll either get a hash or a record (most likely a record), but in the others you could just get query criteria.