Created
August 14, 2009 21:51
-
-
Save thomaslang/168127 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
| // ========================================================================== | |
| // Project: SproutCore - JavaScript Application Framework | |
| // Copyright: ©2006-2009 Sprout Systems, Inc. and contributors. | |
| // Portions ©2008-2009 Apple, Inc. All rights reserved. | |
| // License: Licened under MIT license (see license.js) | |
| // ========================================================================== | |
| //Set these require statements if put into frameworks/datastore/models: | |
| //sc_require('models/record'); | |
| //sc_require('models/record_attribute'); | |
| /** @class | |
| This is used to set up a 'to many' relationship from one model to another. | |
| In contrast to the SC.Record.toMany relation, you don't have to store an | |
| array of related records as a property on your model. | |
| With this toManyByKey relation you can keep track of all records that have | |
| a toOne relation to your record. You can do this either by giving a foreign | |
| key on the related model or by specifying a complete query to find the | |
| related records. | |
| Additionally you can define in which order the related records should be. | |
| This record attribute will give a record array of related records. This | |
| array is computed by a query, will allways be up to date with your store | |
| and is by its nature not editable. To declare two records related you will | |
| have to use the toOne side of the relation. | |
| For this to work, you need to define a corrresponding toOne attribute on | |
| the SC.Record class the related records belong to. | |
| Example usage: | |
| To establish a bidirectional relationship between a user and a message model | |
| you will have to put the following lines inside your model definitions: | |
| {{{ | |
| MyApp.User = SC.Record.extend({ | |
| messages: SC.Record.toManyByKey('MyApp.Message', 'user') | |
| }) | |
| MyApp.Message = SC.Record.Extend({ | |
| user: SC.Record.toOne('MyApp.User') | |
| }) | |
| }}} | |
| To define an order for the related records, use the orderBy option: | |
| {{{ | |
| messages: SC.Record.toManyByKey('MyApp.Message', 'user', | |
| {orderBy: 'priority DESC'}) | |
| }}} | |
| If your related models aren't simply found by a foreign key you can use a | |
| full SC.Query to establish the relationship instead of the foreignKey | |
| (which must be NO in this case): | |
| {{{ | |
| allMessages: SC.Record.toManyByKey('MyApp.Message', NO, { | |
| conditions: 'sender = {user} OR reciever = {user}', | |
| parameters: {user: this}, | |
| orderBy: 'priority DESC' | |
| }) | |
| }}} | |
| The first argument of the 'toManyByKey' function will be used as the | |
| query's recordType property. | |
| @author Thomas Langemann | |
| @extends SC.RecordAttribute | |
| @since SproutCore 1.0 | |
| */ | |
| SC.ToManyRelation = SC.RecordAttribute.extend( | |
| /** @scope SC.ToManyRelation.prototype */ { | |
| foreignKey: null, | |
| conditions: null, | |
| parameters: null, | |
| orderBy: null, | |
| // .......................................................... | |
| // LOW-LEVEL METHODS | |
| // | |
| /** @private - adapted for this toMany relationship */ | |
| toType: function(record, key, value) { | |
| var conditions; | |
| var parameters; | |
| var foreignKey = this.get('foreignKey'); | |
| var orderBy = this.get('orderBy'); | |
| var recordType = this.get('typeClass'); | |
| var store = record.get('store'); | |
| if (foreignKey) { | |
| conditions = foreignKey + " = %@"; | |
| parameters = [record]; | |
| } | |
| else { | |
| conditions = this.get('conditions'); | |
| parameters = this.get('parameters'); | |
| foreignKey = conditions; // used to create uniq cacheKey | |
| } | |
| var queryCacheKey = '__many_query__'+SC.guidFor(recordType)+"__"+foreignKey; | |
| var query = record[queryCacheKey]; | |
| var recsCacheKey = '__many_records__'+SC.guidFor(recordType)+"__"+foreignKey; | |
| var recs = record[recsCacheKey] ; | |
| if (!query) { | |
| query = record[queryCacheKey] = SC.Query.create({ | |
| recordType: recordType, | |
| conditions: conditions, | |
| parameters: parameters, | |
| orderBy: orderBy | |
| }); | |
| } | |
| if (!recs) { | |
| recs = record[recsCacheKey] = record.get('store').findAll(query); | |
| } | |
| return recs ; | |
| } | |
| }); | |
| // The following should go into datastore/models/record.js | |
| SC.Record.mixin( /** @scope SC.Record */ { | |
| /** | |
| Helper method returns a new SC.ToManyRelation instance to establish a | |
| to many relationship. You should pass the type class of the related | |
| records and a foreign key that holds the id of this record. | |
| Alternatively you can pass NO as foreignKey and provide conditions | |
| and parameters in the options to create a SC.Query that will be used | |
| to compute the array of related records. | |
| Use this helper when you define SC.Record subclasses. | |
| @param {Class} type the type of the related records | |
| @param {String} foreignKey the foreign key on the related model | |
| @param {Hash} opts the options for the relation | |
| @returns {SC.RecordAttribute} created instance | |
| */ | |
| toManyByKey: function(type, foreignKey, opts) { | |
| if (!opts) opts = {} ; | |
| opts.type = type; | |
| opts.foreignKey = foreignKey; | |
| return SC.ToManyRelation.create(opts); | |
| } | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment