Created
October 7, 2010 18:11
-
-
Save ghinch/615571 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Book = Y.Base.create('book', Y.Model, [], {}, { | |
PRIMARY_KEY : 'id', | |
ATTRS : { | |
author : {}, | |
id : {}, | |
title : {}, | |
published : {}, | |
format : {} | |
} | |
}); | |
var BookSource = new Y.DataSource.Local({ | |
source : '/fetch/books/', | |
plugins : [ | |
{fn : Y.Plugin.DataSourceArraySchema, cfg : {schema : {}}}, | |
{fn : Y.Plugin.DataSourceModelMapper, cfg : { | |
model : Book, | |
map : { | |
id : 'id', | |
author_id : 'author', | |
book_title : 'title', | |
published : 'published' | |
} | |
}} | |
] | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
YUI.add('model-mapper', function (Y) { | |
Y.namespace('Plugin').DataSourceModelMapper = Y.Base.create('model-mapper', Y.Plugin.Base, [], { | |
_mapData : function (data) { | |
var map = this.get('map'), | |
mappedData = (map ? {} : data); | |
Y.Object.each(map, function (val, key, obj) { | |
if (key in data) { | |
mappedData[val] = data[key]; | |
} | |
}); | |
return mappedData; | |
}, | |
_resultsToModels : function (results) { | |
var resultSet = [], | |
model = this.get('model'); | |
Y.Array.each(results, Y.rbind(function (result, index, arr) { | |
var data = this._mapData(result), | |
m = (model ? new model(data) : data); | |
if (m) { | |
resultSet.push(m); | |
} | |
}, this)); | |
return resultSet; | |
}, | |
_beforeDefResponseFn : function (e) { | |
var results = e.response.results; | |
if (results) { | |
e.response.results = this._resultsToModels(results); | |
} else { | |
e.response.results = []; | |
} | |
Y.DataSource.Local.issueCallback(e, this); | |
return new Y.Do.Halt("ModelManager plugin halted defResponseFn"); | |
}, | |
initializer : function () { | |
this.doBefore('_defResponseFn', this._beforeDefResponseFn); | |
} | |
}, { | |
NS : 'mapper', | |
ATTRS : { | |
map : {}, | |
model : {} | |
} | |
}); | |
}, '', {requires : ['collection', 'base-build', 'datasource-local', 'plugin']}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
YUI.add('model', function (Y) { | |
Y.Model = Y.Base.create('model', Y.Base, [], { | |
_id : null, | |
// These methods allow setters to be strings for primitive types | |
'string' : function (val, key) { | |
return String(val); | |
}, | |
'number' : function (val, key) { | |
return Number(val); | |
}, | |
'date' : function (val, key) { | |
return new Date(val); | |
}, | |
initializer : function (cfg) { | |
this.once('initializedChange', function (e) { | |
var c = this.constructor, | |
id = this.get('_id'); | |
if (!c._instances) { | |
c._instances = {}; | |
} | |
c._instances[id] = this; | |
}, this); | |
}, | |
destructor : function () { | |
var c = this.constructor, | |
id = this.get('_id'); | |
delete c._instances[id]; | |
}, | |
// Compare if two instances are the same by turning them into objects and comparing them as JSON. | |
// Would be nice if we had md5 here... this may have problems though, if Model references are included, | |
// may just need to do top level comparison | |
compare : function (other) { | |
if (!other instanceof this.constructor) { | |
return false; | |
} | |
var selfHash = Y.JSON.stringify(this.toObject()), | |
otherHash = Y.JSON.stringify(other.toObject()); | |
return selfHash == otherHash; | |
}, | |
// Turns this model instance into a Javascript object which can be serialized into another data format | |
toObject : function () { | |
var c = this.constructor, | |
members = c.members(), | |
obj = {}; | |
Y.Array.each(members, function (member) { | |
obj[member] = this.get(member); | |
}, this); | |
return obj; | |
} | |
}, { | |
NS : 'model', | |
ATTRS : { | |
primaryKey : { | |
readOnly : true, | |
valueFn : function () { | |
return this.constructor.PRIMARY_KEY; | |
} | |
}, | |
'_id' : { | |
readOnly : true, | |
getter : function () { | |
var pk = this.get('primaryKey'), | |
id = (pk ? this.get(pk) : null); | |
if (!id) { | |
if (!this._id) { | |
this._id = Y.guid(); | |
} | |
id = this._id; | |
} | |
return id; | |
} | |
} | |
}, | |
getById : function (id) { | |
return this._instances[id]; | |
}, | |
// Class method for returning a list of all the member properties (ATTRS) of this constructor, | |
// up the inheritance chain | |
members : function () { | |
var c = this.prototype.constructor, | |
map = []; | |
while (c) { | |
try { | |
if (c.ATTRS) { | |
Y.Object.each(c.ATTRS, function (val, key) { | |
if (!val.readOnly) { | |
map.push(key); | |
} | |
}); | |
} | |
} catch (err) {} | |
c = (c.superclass ? c.superclass.constructor : null); | |
} | |
return map; | |
}, | |
// Utility method to create a reference to another Model constructor as the | |
// value to set for a property. | |
// @TODO : Look into making this lazy to a remote source | |
reference : function (model) { | |
if (model.prototype) { | |
function createModel (o, key, construct) { | |
try { | |
if (Y.Lang.isString(o) || Y.Lang.isNumber(o)) { | |
return construct.getById(o); | |
} else { | |
return new construct(cfg); | |
} | |
} catch (err) {} | |
} | |
return Y.rbind(createModel, this, model); | |
} | |
}, | |
// Same as above but creates an array of Models rather than just one | |
referenceMany : function (model) { | |
if (model.prototype) { | |
function createModels (cfg, key, construct) { | |
var data = []; | |
try { | |
Y.Array.each(cfg, function (o) { | |
data.push((Y.Lang.isString(o) || Y.Lang.isNumber(o)) ? construct.getById(o) : new construct(o)); | |
}); | |
} finally { | |
return data; | |
} | |
} | |
return Y.rbind(createModels, this, model); | |
} | |
} | |
}); | |
function isModel (o) { | |
var c = o.superclass.constructor; | |
while (c.superclass) { | |
if (c == Y.Model) { | |
return true | |
} | |
c = c.superclass.constructor; | |
} | |
return false; | |
} | |
// Propogates additional data needed for models | |
Y.mix(Y.Base._buildCfg.custom, { | |
getById : function (prop, r, s) { | |
if (isModel(r)) { | |
r.getById = Y.Model.getById; | |
} | |
}, | |
members : function (prop, r, s) { | |
if (isModel(r)) { | |
r.members = Y.Model.members; | |
} | |
} | |
}); | |
}, '', {requires : ['base-build', 'datatype-date', 'json-stringify']}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment