// ========================================================================== // 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) // ========================================================================== /** @class A RecordArray wraps an array of storeKeys, converting them into materialized record objects from the owner store on demand. A Record Array instance is usually returned when you call SC.Store#findAll() or SC.Store#recordsFor(). @extends SC.Object @extends SC.Enumerable @extends SC.Array @since SproutCore 1.0 */ SC.RecordArray = SC.Object.extend(SC.Enumerable, SC.Array, /** @scope SC.RecordArray.prototype */ { /** The store that owns this record array. All record arrays must have a store to function properly. @property {SC.Store} */ store: null, /** SC.Array object that will provide the store keys for the array. The record array will register itself as an observer for this array. @property {SC.Array} */ storeKeys: null, /** SC.Query object that is set if record array is based on a query. Whenever the store keys content change, the SC.Query will be reapplied so that only matching storeKeys are set on the record array. @property {SC.Query} */ queryKey: null, /** The current load state of the RecordArray. If the storeKeys has a state property, then this property will return that value. Otherwise it returns SC.Record.READY. */ state: function() { var storeKeys = this.get('storeKeys'), ret = (storeKeys && !SC.none(storeKeys.state)) ? storeKeys.get('state') : null; return ret ? ret : SC.Record.READY; }.property().cacheable(), /** @private Cache of records returned from objectAt() so they don't need to be unneccesarily materialized. @property {SC.Query} */ _records: null, // .......................................................... // ARRAY PRIMITIVES // /** Returned length is a pass-through to the storeKeys array. */ length: function() { var storeKeys = this.get('storeKeys'); return storeKeys ? storeKeys.get('length') : 0; }.property('storeKeys').cacheable(), /** Looks up the store key in the store keys array and materializes a records. @param {Number} idx index of the object @return {SC.Record} materialized record */ objectAt: function(idx) { var recs = this._records, storeKeys = this.get('storeKeys'), store = this.get('store'), storeKey, ret ; if (!storeKeys || !store) return undefined; // nothing to do if (recs && (ret=recs[idx])) return ret ; // cached // not in cache, materialize if (!recs) this._records = recs = [] ; // create cache storeKey = storeKeys.objectAt(idx); if (storeKey) { // if record is not loaded already, then ask the data source to // retrieve it if (store.readStatus(storeKey) === SC.Record.EMPTY) { store.retrieveRecord(null, null, storeKey); } recs[idx] = ret = store.materializeRecord(storeKey); } return ret ; }, /** Pass through to the underlying array. The passed in objects must be records, which can be converted to storeKeys. @param {Number} idx start index @param {Number} amt end index @param {SC.RecordArray} recs to replace with records @return {SC.RecordArray} 'this' after replace */ replace: function(idx, amt, recs) { var storeKeys = this.get('storeKeys'), len = recs ? (recs.get ? recs.get('length') : recs.length) : 0, i, keys; if (!storeKeys) throw "storeKeys required"; // map to store keys keys = [] ; for(i=0;i