Skip to content

Instantly share code, notes, and snippets.

@Zaggen
Last active May 13, 2016 04:58
Show Gist options
  • Save Zaggen/63f2a132180806ae0cd577c328b3373e to your computer and use it in GitHub Desktop.
Save Zaggen/63f2a132180806ae0cd577c328b3373e to your computer and use it in GitHub Desktop.
WIP: Backbone base model, that adds schema system with associations
class App.Models.Base extends Backbone.Model
schema: {}
set: (attributes, options)->
if _.isString(attributes)
[key, val] = [attributes, options]
(attributes = {})[key] = val
options = null
super(@filter(attributes), options)
validate: (attrs)->
# Here we should iterate on all attributes in our schema,
# first validating presence of (required), then type, and then the rest
###errorObj = {}
for attrName, options of @schema
if attrs[attrName]?
@_types[options.type](attrs[attrName])
else
if options.required
errorObj[attrName] = {'rule': 'required', msg: "This field is required but its not defined"}
if not _.isEmpty(errorObj)
return errorObj
else
return null###
return null
# Parses model attributes to validate its types and applies filtering
# and transformations if those were set.
filter: (attrs)->
if @schema
filteredAttrs = {}
for attrName, attrOptions of @schema
#TODO: Take into account boolean and null values that could be valid
if attrOptions.collection and _.isArray(attrs[attrName])
@_filterCollection(filteredAttrs, attrs, attrOptions, attrName) if attrs[attrName]?
else if attrOptions.model
@_filterModel(filteredAttrs, attrs, attrOptions, attrName) if attrs[attrName]?
else if (value = if attrs[attrName]? then attrs[attrName] else attrOptions.defaultsTo)?
filteredAttrs[attrName] =
if _.isEmpty(attrOptions.filters) then value
else
_.reduce(attrOptions.filters,((a, filterName)=> @_filters[filterName](value)), value)
#TODO: Implement whitelisting attributes
# _whiteListedAttributes
return filteredAttrs
else
return attributes
_filterCollection: (filteredAttrs, attrs, attrOptions, attrName)->
#@_filterRelation(Array::concat.call(arguments, 'collection', 'Collections')...)
@_filterRelation(filteredAttrs, attrs, attrOptions, attrName, 'collection', 'Collections')
_filterModel: (filteredAttrs, attrs, attrOptions, attrName)->
#@_filterRelation(Array::concat.call(arguments, 'model', 'Models')...)
@_filterRelation(filteredAttrs, attrs, attrOptions, attrName, 'model', 'Models')
_filterRelation: (filteredAttrs, attrs, attrOptions, attrName, relationType, relationNameSpace)->
# When the passed attribute (new) is already an instance of certain model or collection
# we can safely assign it to the specified attribute slot (No further processing)
if attrs[attrName] instanceof App[relationNameSpace][attrOptions[relationType]]
filteredAttrs[attrName] = attrs[attrName]
else
# When the passed attribute is not an instance of the specified model/collection we
# must parse it. The passed attribute could either be an object or array of objects with
# the expected format. If there is already a model/collection with that attribute name
# on this model, we use set, if there is not then we must create the proper instance
if @get(attrName) instanceof App[relationNameSpace][attrOptions[relationType]]
@get(attrName).set(attrs[attrName])
else
filteredAttrs[attrName] = new App[relationNameSpace][attrOptions[relationType]](attrs[attrName])
return filteredAttrs
_types:
string: (attributeName, value)-> _.isString(value)
int: (attributeName, value)-> _.isInteger(value)
array: (attributeName, value)-> _.isArray(value)
json: (attributeName, value)-> _.isObject(value)
object: (attributeName, value)-> _.isObject(value)
date: (attributeName, value)-> true # Not implemented yet
_errorMessages:
string: (k, v)-> "#{k}(#{typeof v}) is not a string"
int: (k, v)-> "#{k}(#{typeof v}) is not an integer"
array: (k, v)-> "#{k}(#{typeof v}) is not an array"
json: (k, v)-> "#{k}(#{typeof v}) is not an object"
object: (k, v)-> "#{k}(#{typeof v}) is not an object"
date: (k, v)-> "#{k}(#{typeof v}) is not a Date"
_validations:
notEmpty: ->
required: (attributeName, value)-> if value? then true else "#{attributeName} is required"
_filters:
trim: (string)-> string.trim()
nestedTrim: (obj)->
for k, v of obj
obj[k] = v.trim()
return obj
# This values won't be stripped by filter even if they don't appear on the schema
_whiteListedAttributes: ['id' ,'_csrf', '_method']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment