Skip to content

Instantly share code, notes, and snippets.

@ColinCampbell
Created March 30, 2011 03:02
Show Gist options
  • Select an option

  • Save ColinCampbell/893784 to your computer and use it in GitHub Desktop.

Select an option

Save ColinCampbell/893784 to your computer and use it in GitHub Desktop.
diff --git a/frameworks/datastore/models/record.js b/frameworks/datastore/models/record.js
index 58a15aa..8245552 100644
--- a/frameworks/datastore/models/record.js
+++ b/frameworks/datastore/models/record.js
@@ -900,6 +900,29 @@ SC.Record.mixin( /** @scope SC.Record */ {
*/
ignoreUnknownProperties: NO,
+ /**
+ If YES, then searches for records of this type will return
+ subclass instances. For example:
+
+ {{{
+ Person = SC.Record.extend();
+ Person.isPolymorphic = YES;
+
+ Male = Person.extend();
+ Female = Person.extend();
+ }}}
+
+ Using SC.Store#find, or a toOne or toMany relationship on
+ Person will then return records of type Male and Female.
+ Polymorphic record types must have unique GUIDs for all
+ subclasses.
+
+ @property {Boolean}
+ @default NO
+ */
+ isPolymorphic: NO,
+
+
// ..........................................................
// CONSTANTS
//
@@ -1254,7 +1277,9 @@ SC.Record.mixin( /** @scope SC.Record */ {
storeKeysById: function() {
var key = SC.keyFor('storeKey', SC.guidFor(this)),
ret = this[key];
+
if (!ret) ret = this[key] = {};
+
return ret;
},
@@ -1271,13 +1296,14 @@ SC.Record.mixin( /** @scope SC.Record */ {
*/
storeKeyFor: function(id) {
var storeKeys = this.storeKeysById(),
- ret = storeKeys[id];
+ ret = storeKeys[id];
if (!ret) {
ret = SC.Store.generateStoreKey();
- SC.Store.idsByStoreKey[ret] = id ;
- SC.Store.recordTypesByStoreKey[ret] = this ;
- storeKeys[id] = ret ;
+ SC.Store.idsByStoreKey[ret] = id;
+ SC.Store.recordTypesByStoreKey[ret] = this;
+ storeKeys[id] = ret;
+ this._propagateIdForStoreKey(id, ret);
}
return ret ;
@@ -1314,5 +1340,39 @@ SC.Record.mixin( /** @scope SC.Record */ {
var ret = SC.Object.extend.apply(this, arguments);
SC.Query._scq_didDefineRecordType(ret);
return ret ;
+ },
+
+
+ // ..........................................................
+ // Internal Support
+ //
+
+ /** @private */
+ _propagateIdForStoreKey: function(id, storeKey) {
+ var superclass = this.superclass;
+ if (this.isPolymorphic) {
+ while (superclass.isPolymorphic && superclass !== SC.Record) {
+ superclass._storeKeyForId(storeKey, id);
+ superclass = superclass.superclass;
+ }
+ }
+ },
+
+ /** @private */
+ _storeKeyForId: function(storeKey, id) {
+ var storeKeys;
+ if (!this.isPolymorphic) return;
+
+ /*
+ TODO [CC] SC.Store.recordTypesByStoreKey will be broken
+ */
+
+ storeKeys = this.storeKeysById();
+ if (storeKeys[id]) {
+ throw "A store key (%@) already existing for %@ on %@".fmt(storeKey, id, this);
+ }
+
+ storeKeys[id] = storeKey;
}
-}) ;
+
+});
// ==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2006-2010 Apple Inc. and contributors.
// License: Licensed under MIT license (see license.js)
// ==========================================================================
/*globals module ok equals same test MyApp */
(function() {
var store, Person, Male, Female, colin, maggie;
module("Polymorphic SC.Record - Simple", {
setup: function() {
SC.RunLoop.begin();
store = SC.Store.create();
Person = SC.Record.extend();
Person.isPolymorphic = YES;
Male = Person.extend({
isMale: YES
});
Female = Person.extend({
isFemale: YES
});
colin = store.createRecord(Male, {
guid: '1'
});
maggie = store.createRecord(Female, {
guid: '2'
});
},
teardown: function() {
store = Person = Male = Female = colin = maggie = null;
SC.RunLoop.end();
}
});
test("SC.Store#find works with abstract record type", function() {
var person1 = store.find(Person, '1'),
person2 = store.find(Person, '2');
equals(person1, colin, "find on Person record type with guid 1 should return male record");
ok(SC.kindOf(person1, Male) && person1.isMale, "returned record should be of type Male");
equals(person2, maggie, "find on Person record type with guid 2 should return female record");
ok(SC.kindOf(person2, Female) && person2.isFemale, "returned record should be of type Female");
});
test("Creating a record of a different concrete type with the same id errors", function() {
expect(1);
try {
store.createRecord(Female, {
guid: '1'
});
} catch (e) {
ok(true, "Error occured when trying to create type with same guid");
}
});
})();
// ==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2006-2010 Apple Inc. and contributors.
// License: Licensed under MIT license (see license.js)
// ==========================================================================
/*globals module ok equals same test MyApp */
(function() {
var store, Employee, Company, Engineer, Executive, Accountant, Other,
strobe, colin, charles, matt, yehuda, erin, digits;
module("Polymorphic SC.Record - toMany tests", {
setup: function() {
SC.RunLoop.begin();
store = SC.Store.create();
Employee = SC.Record.extend({
name: SC.Record.attr(String)
});
Employee.isPolymorphic = YES;
Company = SC.Record.extend({
name: SC.Record.attr(String),
employees: SC.Record.toMany(Employee, {inverse: 'company'})
});
Engineer = Employee.extend({
isEngineer: YES
});
Executive = Employee.extend({
isExecutive: YES
});
Accountant = Employee.extend({
isAccountant: YES
});
Other = Employee.extend({
isOther: YES
});
strobe = store.createRecord(Company, {
name: "Strobe",
employees: ['1', '2', '3', '4', '5', '6']
});
colin = store.createRecord(Engineer, {guid: '1', name: 'Colin'});
yehuda = store.createRecord(Engineer, {guid: '2', name: 'Yehuda'});
charles = store.createRecord(Executive, {guid: '3', name: 'Charles'});
matt = store.createRecord(Executive, {guid: '4', name: 'Matt'});
erin = store.createRecord(Other, {guid: '5', name: 'Erin'});
digits = store.createRecord(Accountant, {guid: '6', name: 'P. Diggy'});
},
teardown: function() {
store = Employee = Company = Engineer = Executive = Accountant = Other = null;
strobe = colin = charles = matt = yehuda = erin = digits = null;
SC.RunLoop.end();
}
});
function testRecord(record, expected) {
equals(record, expected, "Record should be the same as what's expected");
ok(record.constructor === expected.constructor, "Record should be the same subtype as expected");
}
test("toOne relationship returns record of correct type", function() {
var employees = strobe.get('employees');
testRecord(employees.objectAt(0), colin);
testRecord(employees.objectAt(1), yehuda);
testRecord(employees.objectAt(2), charles);
testRecord(employees.objectAt(3), matt);
testRecord(employees.objectAt(4), erin);
testRecord(employees.objectAt(5), digits);
});
})();
// ==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2006-2010 Apple Inc. and contributors.
// License: Licensed under MIT license (see license.js)
// ==========================================================================
/*globals module ok equals same test MyApp */
(function() {
var store, Person, Place, Male, Female, home, colin, maggie;
module("Polymorphic SC.Record - toOne tests", {
setup: function() {
SC.RunLoop.begin();
store = SC.Store.create();
Person = SC.Record.extend({
name: SC.Record.attr(String)
});
Person.isPolymorphic = YES;
Place = SC.Record.extend({
where: SC.Record.attr(String),
person: SC.Record.toOne(Person, {inverse: 'place'})
});
Male = Person.extend({
isMale: YES
});
Female = Person.extend({
isFemale: YES
});
home = store.createRecord(Place, {
guid: '0',
where: 'Canada',
person: '1'
});
colin = store.createRecord(Male, {
guid: '1',
name: 'Colin'
});
maggie = store.createRecord(Female, {
guid: '2',
name: 'Maggie'
});
},
teardown: function() {
store = Person = Place = Male = Female = home = colin = maggie = null;
SC.RunLoop.end();
}
});
test("toOne relationship returns record of correct type", function() {
equals(home.get('person'), colin, "Correct record is returned for polymorphic relationship");
ok(SC.kindOf(home.get('person'), Male), "Correct record type is returned for polymorphic relationship");
});
test("setting toOne relationship works", function() {
home.set('person', maggie);
ok(SC.kindOf(home.get('person'), Female), "Changing toOne to record of different type works");
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment