Skip to content

Instantly share code, notes, and snippets.

@mattetti
Created August 22, 2011 22:00
Show Gist options
  • Save mattetti/1163733 to your computer and use it in GitHub Desktop.
Save mattetti/1163733 to your computer and use it in GitHub Desktop.
DS = SC.Namespace.create();
DS.property = function(transforms) {
return SC.computed(function(key, value) {
var data = get(this, 'data'), value, val,
name = transforms.keyName || key;
var from = transforms && transforms.from;
var to = transforms && transforms.to;
// if the data hasn't been populated yet, return immediately
if (!data) { return; }
if (value !== undefined) {
val = to ? to(value) : value;
SC.set(data, name, val);
} else {
value = SC.get(data, name);
if (from) { value = from(value); }
}
return value;
}).property('data')
};
DS.property.string = DS.property;
DS.property.integer = function(keyName) {
return DS.property({
keyName: keyName,
from: function(serialized) {
return Number(serialized);
},
to: function(deserialized) {
return String(deserialized);
}
});
};
DS.property.date = function(keyName) {
return DS.property({
keyName: keyName,
from: function(raw) {
return new Date(raw);
},
to: function(date) {
return JSON.stringify(date);
}
})
};
DS.hasMany = function(other, klass) {
return function() {
var keys = SC.get(this.get('data'), other);
if (keys) {
var recordArray = SC.ArrayProxy.create(), content = [];
keys.forEach(function(key) {
content.push(klass.load(key));
})
recordArray.set('content', content);
return recordArray;
} else {
return;
}
}.property('data.' + other + '.@each').cacheable()
};
DS.RecordArray = SC.Object.extend(SC.Array, {
keys: null,
objectAt: function(idx) {
var keys = this.get('keys'),
klass = this.get('klass');
if (!keys) { return; }
var id = keys.objectAt(idx);
return klass.loadRecord(id);
}
});
DS.Record = SC.Object.extend({
unknownProperty: function(key, value) {
var data = this.get('data');
if (value !== undefined) {
SC.set(data, key, value);
} else {
value = SC.get(data, key);
}
return value;
},
save: function() {
DS.saveRecord(this);
}
});
DS.RECORDS = {};
DS.recordHashFor = function(klass, id) {
var recordsHash = DS.RECORDS[SC.guidFor(klass)];
if (!recordsHash) { DS.RECORDS[SC.guidFor(klass)] = {} }
return recordsHash[id];
};
DS.setRecordHash = function(klass, id, hash) {
var recordsHash = DS.RECORDS[SC.guidFor(klass)];
if (!recordsHash) { DS.RECORDS[SC.guidFor(klass)] = {}; recordsHash = {} }
recordsHash[id] = hash;
};
// default method to look up a record by class and id.
// a record class can define its own load method for special behavior
//
// you can override this method to change the global loading behavior
DS.loadRecord = function(klass, id, force) {
var url = klass['instanceUrl'].fmt(id),
resource = klass['resource'],
instance = klass.create();
if (!force) {
var recordHash = DS.recordHashFor(klass, id);
if (recordHash) { return instance.set('data', recordHash); }
}
$.ajax({
url: url,
dataType: 'json',
success: function(json) {
DS.setRecordHash(klass, id, json[resource]);
instance.set('data', json[resource]);
}
});
return instance;
};
// params can be a Hash or a URL-encoded String
DS.loadRecords = function(klass, params) {
var url = klass['collectionUrl'],
resource = klass['resource'],
recordArray = SC.ArrayProxy.create();
$.ajax({
url: url,
data: params,
dataType: 'json',
success: function(json) {
var rawArray = json[resource], array = [];
rawArray.forEach(function(item) {
DS.setRecordHash(klass, item.id, item);
array.push(klass.create({ data: item }));
});
recordArray.set('content', array);
}
});
// Return the recordArray right away. It will asynchronously
// be populated with data when the data comes in via Ajax
return recordArray;
}
DS.saveRecord = function(record) {
var url = SC.get(this.constructor, 'instanceUrl');
url = url.fmt(this.get('id'));
// TODO: Something on success vs. failure
$.ajax({
type: 'PUT',
url: url,
data: SC.get(this, 'data'),
dataType: 'json',
});
}
DS.Record.reopenClass({
// force forces the record to be loaded even if it's already
// been fetched
load: function(id, force) {
return DS.loadRecord(this, id, force);
},
// fetches all records. You can specify params as a Hash or
// URL-encoded string to narrow down the results. Returned
// records will override existing records
//
// TODO: Make sure instantiated objects get the updated
// data hashes.
loadAll: function(params) {
return DS.loadRecords(this, params);
}
});
/**
USAGE
// TODO: Convention over configuration for instance URL, resource
// name and class URL
Person = DS.Record.extend({
firstName: DS.property.string(),
lastName: DS.property.string(),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
Person.reopenClass({
collectionUrl: "/people",
instanceUrl: "/people/%@",
resource: "people"
});
var person = Person.load(1);
var people = Person.loadAll(); // can use this wherever an
// Array is expected, like in
// an ArrayController
*/
@jamesarosen
Copy link

Totally understood, and thanks for posting this!

I'm mostly thinking out loud here so we can collectively converge. @staugaard and @shajith have been working on a similar library today and will be stealing the best ideas from here. @wycats and I have planned to reconvene later this week to polish and release.

@jamesarosen
Copy link

Some updates & fixes by the above-mentioned @staugaard and @shajith are available here: https://gist.github.com/1167122

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment