Created
March 30, 2011 03:02
-
-
Save ColinCampbell/893784 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| 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; | |
| } | |
| -}) ; | |
| + | |
| +}); | |
This file contains hidden or 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
| // ========================================================================== | |
| // 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"); | |
| } | |
| }); | |
| })(); |
This file contains hidden or 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
| // ========================================================================== | |
| // 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); | |
| }); | |
| })(); |
This file contains hidden or 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
| // ========================================================================== | |
| // 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