UNPKG

tiger

Version:

A full port of Spine.js MVC framework to Titanium Mobile, with enhancements

338 lines (256 loc) 8.55 kB
Tiger = @Tiger or require('./tiger') isArray = Tiger.isArray class BaseCollection extends Tiger.Class constructor: (options = {}) -> for key, value of options @[key] = value first: -> @all()[0] last: -> values = @all() values[values.length - 1] create: (record) -> newRecord = @model.create(record) (@add newRecord) if newRecord class Collection extends BaseCollection add: (fItem) -> fItem[@fkey] = @record.id fItem.save() remove: (fItem) -> fItem = @find(fItem) if typeof fItem is 'string' fItem.destroy() all: -> @model.select (rec) => @associated(rec) find: (id) -> records = @select (rec) => rec.id + '' is id + '' throw('Unknown record') unless records[0] records[0] findAllByAttribute: (name, value) -> @model.select (rec) => @associated(rec) and rec[name] is value findByAttribute: (name, value) -> @findAllByAttribute(name, value)[0] select: (cb) -> @model.select (rec) => @associated(rec) and cb(rec) refresh: (values) -> delete @model.records[record.id] for record in @all() records = @model.fromJSON(values) records = [records] unless isArray(records) for record in records record.newRecord = false record[@fkey] = @record.id @model.records[record.id] = record @model.trigger('refresh', @model.cloneArray(records)) # Private associated: (record) -> record[@fkey] is @record.id class O2MCollection extends BaseCollection add: (item, save = true) -> if isArray(item) @add i, false for i in item else item = @model.find item unless item instanceof @model @record[@lkey].push item[@fkey] @record.save() if save remove: (item) -> item = @model.find item unless item instanceof @model @record[@lkey].splice (@record[@lkey].indexOf item[@fkey]), 1 @record.save() all: -> (@model.find lkey for lkey in @record[@lkey]) find: (id) -> id in @record[@lkey] and @model.find id or throw 'Unknown record' class M2MCollection extends BaseCollection add: (item, save = true) -> if isArray(item) @add i, false for i in item else item = @model.find item unless item instanceof @model hub = new @Hub() if @left_to_right hub["#{@rev_name}_id"] = @record.id hub["#{@name}_id"] = item.id else hub["#{@rev_name}_id"] = item.id hub["#{@name}_id"] = @record.id hub.save() if save remove: (item) -> i.destroy() for i in @Hub.select (item) => @associated(item) _link: (items) -> items.map (item) => if @left_to_right then return @model.find item["#{@name}_id"] else return @model.find item["#{@rev_name}_id"] all: -> @_link @Hub.select (item) => @associated(item) find: (id) -> records = @Hub.select (rec) => @associated(rec, id) throw 'Unknown record' unless records[0] @_link(records)[0] associated: (record, id) -> if @left_to_right return false unless record["#{@rev_name}_id"] is @record.id return record["#{@rev_name}_id"] is id if id else return false unless record["#{@name}_id"] is @record.id return record["#{@name}_id"] is id if id true class Instance extends Tiger.Class constructor: (options = {}) -> for key, value of options @[key] = value exists: -> @record[@fkey] and @model.exists(@record[@fkey]) update: (value) -> unless value instanceof @model value = new @model(value) value.save() if value.isNew() @record[@fkey] = value and value.id @record.save() class Singleton extends Tiger.Class constructor: (options = {}) -> for key, value of options @[key] = value find: -> @record.id and @model.findByAttribute(@fkey, @record.id) update: (value) -> unless value instanceof @model value = @model.fromJSON(value) value[@fkey] = @record.id value.save() singularize = (str) -> str.replace(/s$/, '') underscore = (str) -> str.replace(/::/g, '/') .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') .replace(/([a-z\d])([A-Z])/g, '$1_$2') .replace(/-/g, '_') .toLowerCase() loadModel = (model, parent) -> if typeof model is 'string' model = require(model) model.bind 'error', (record, msg) => parent.trigger 'error', record, msg, model.className if typeof model.loadTigerDB is 'function' model.bindTigerDB().fetch() model Relations = __filter: (args, revert=false) -> (rec) -> q = !!revert for key, value of args return q unless rec[key] is value !q filter: (args) -> @select @__filter args exclude: (args) -> @select @__filter args, true oneToMany: (model, name, fkey) -> parent = @ unless name? model = loadModel model, parent name = model.className.toLowerCase() name = singularize underscore name lkey = "#{name}_ids" unless lkey in @attributes @attributes.push lkey fkey ?= 'id' association = (record, model) -> model = loadModel model, parent record[lkey] = [] unless record[lkey] new O2MCollection {lkey, fkey, record, model} @::["#{name}s"] = (value) -> association(@, model) hasMany: (model, name, fkey) -> parent = @ unless name? model = loadModel model, parent name = model.className.toLowerCase() name = singularize underscore name fkey ?= "#{underscore(this.className)}_id" association = (record) -> model = loadModel model, parent new Collection( name: name, model: model, record: record, fkey: fkey ) @::["#{name}s"] = (value) -> association(@).refresh(value) if value? association(@) belongsTo: (model, name, fkey) -> parent = @ unless name? model = loadModel model, parent name = model.className.toLowerCase() name = singularize underscore name fkey ?= "#{name}_id" association = (record) -> model = loadModel model, parent new Instance( name: name, model: model, record: record, fkey: fkey ) @::[name] = (value) -> association(@).update(value) if value? association(@).exists() @attributes.push(fkey) hasOne: (model, name, fkey) -> parent = @ unless name? model = loadModel model, parent name = model.className.toLowerCase() name = singularize underscore name fkey ?= "#{underscore(@className)}_id" association = (record) -> model = loadModel model, parent new Singleton( name: name, model: model, record: record, fkey: fkey ) @::[name] = (value) -> association(@).update(value) if value? association(@).find() foreignKey: (model, name, rev_name) -> parent = @ unless name? model = loadModel model, parent name = model.className.toLowerCase() name = singularize underscore name unless rev_name? rev_name = @className.toLowerCase() rev_name = singularize underscore rev_name rev_name = "#{rev_name}s" @belongsTo name, model model.hasMany rev_name, @ manyToMany: (model, name, rev_name) -> parent = @ unless name? model = loadModel model, parent name = model.className.toLowerCase() name = singularize underscore name unless rev_name? rev_name = @className.toLowerCase() rev_name = singularize underscore rev_name rev_name = "#{rev_name}s" rev_model = @ local = typeof model.loadLocal is 'function' or typeof rev_model.loadLocal is 'function' tigerDB = typeof model.loadTigerDB is 'function' or typeof rev_model.loadTigerDB is 'function' class Hub extends Tiger.Model @extend Tiger.Model.Local if local @extend Tiger.Model.TigerDB if tigerDB @configure "_#{rev_name}_to_#{name}", "#{@rev_name}_id", "#{@name}_id" Hub.fetch() if local or tigerDB Hub.foreignKey rev_model, "#{rev_name}" Hub.foreignKey model, "#{name}" association = (record, model, left_to_right) -> model = loadModel model, parent new M2MCollection {name, rev_name, record, model, Hub: Hub, left_to_right} rev_model::["#{name}s"] = (value) -> association(@, model, true) model::["#{rev_name}s"] = (value) -> association(@, rev_model, false) Tiger.Model.extend Relations Relations.loadModel = loadModel Tiger.Model.Relations = Relations module?.exports = Relations