Created
January 7, 2016 15:25
-
-
Save mauritslamers/d7c5450642da8be9539e to your computer and use it in GitHub Desktop.
Make SC.RecordArray behave conform specifications
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
| SC.RecordArray.prototype.flush = function(_flush) { | |
| // Are we already inside a flush? If so, then don't do it again, to avoid | |
| // never-ending recursive flush calls. Instead, we'll simply mark | |
| // ourselves as needing a flush again when we're done. | |
| if (this._insideFlush) { | |
| this.set('needsFlush', YES); | |
| return this; | |
| } | |
| if (!this.get('needsFlush') && !_flush) return this; // nothing to do | |
| this.set('needsFlush', NO); // avoid running again. | |
| // fast exit | |
| var query = this.get('query'), | |
| store = this.get('store'); | |
| if (!store || !query || query.get('location') !== SC.Query.LOCAL) { | |
| return this; | |
| } | |
| this._insideFlush = YES; | |
| // OK, actually generate some results | |
| var storeKeys = this.get('storeKeys'), | |
| changed = this._scq_changedStoreKeys, | |
| didChange = NO, | |
| K = SC.Record, | |
| storeKeysToPace = [], | |
| startDate = new Date(), | |
| rec, status, recordType, sourceKeys, scope, included; | |
| // if we have storeKeys already, just look at the changed keys | |
| var oldStoreKeys = storeKeys; | |
| if (storeKeys && !_flush) { | |
| if (changed) { | |
| changed.forEach(function(storeKey) { | |
| if(storeKeysToPace.length>0 || new Date()-startDate>SC.RecordArray.QUERY_MATCHING_THRESHOLD) { | |
| storeKeysToPace.push(storeKey); | |
| return; | |
| } | |
| // get record - do not include EMPTY or DESTROYED records | |
| status = store.peekStatus(storeKey); | |
| if (!(status & K.EMPTY) && !((status & K.DESTROYED) || (status === K.BUSY_DESTROYING))) { | |
| rec = store.materializeRecord(storeKey); | |
| included = !!(rec && query.contains(rec)); | |
| } else included = NO ; | |
| // if storeKey should be in set but isn't -- add it. | |
| if (included) { | |
| if (storeKeys.indexOf(storeKey)<0) { | |
| if (!didChange) storeKeys = storeKeys.copy(); | |
| storeKeys.pushObject(storeKey); | |
| } | |
| // if storeKey should NOT be in set but IS -- remove it | |
| } else { | |
| if (storeKeys.indexOf(storeKey)>=0) { | |
| if (!didChange) storeKeys = storeKeys.copy(); | |
| storeKeys.removeObject(storeKey); | |
| } // if (storeKeys.indexOf) | |
| } // if (included) | |
| }, this); | |
| // make sure resort happens | |
| didChange = YES ; | |
| } // if (changed) | |
| // if no storeKeys, then we have to go through all of the storeKeys | |
| // and decide if they belong or not. ick. | |
| } else { | |
| // collect the base set of keys. if query has a parent scope, use that | |
| if (scope = query.get('scope')) { | |
| sourceKeys = scope.flush().get('storeKeys'); | |
| // otherwise, lookup all storeKeys for the named recordType... | |
| } else if (recordType = query.get('expandedRecordTypes')) { | |
| sourceKeys = SC.IndexSet.create(); | |
| recordType.forEach(function(cur) { | |
| sourceKeys.addEach(store.storeKeysFor(cur)); | |
| }); | |
| } | |
| // loop through storeKeys to determine if it belongs in this query or | |
| // not. | |
| storeKeys = []; | |
| sourceKeys.forEach(function(storeKey) { | |
| if(storeKeysToPace.length>0 || new Date()-startDate>SC.RecordArray.QUERY_MATCHING_THRESHOLD) { | |
| storeKeysToPace.push(storeKey); | |
| return; | |
| } | |
| status = store.peekStatus(storeKey); | |
| if (!(status & K.EMPTY) && !((status & K.DESTROYED) || (status === K.BUSY_DESTROYING))) { | |
| rec = store.materializeRecord(storeKey); | |
| if (rec && query.contains(rec)) storeKeys.push(storeKey); | |
| } | |
| }); | |
| didChange = YES ; | |
| } | |
| // if we reach our threshold of pacing we need to schedule the rest of the | |
| // storeKeys to also be updated | |
| if (storeKeysToPace.length > 0) { | |
| this.set('status', SC.Record.BUSY_REFRESH); | |
| this.invokeNext(function () { | |
| if (!this || this.get('isDestroyed')) return; | |
| this.set('needsFlush', YES); | |
| this._scq_changedStoreKeys = SC.IndexSet.create().addEach(storeKeysToPace); | |
| this.flush(); | |
| }); | |
| } | |
| else { | |
| this.set('status', SC.Record.READY_CLEAN); | |
| } | |
| // clear set of changed store keys | |
| if (changed) changed.clear(); | |
| // Clear the flushing flag. | |
| // NOTE: Do this now, because any observers of storeKeys could trigger a call | |
| // to flush (ex. by calling get('length') on the RecordArray). | |
| this._insideFlush = NO; | |
| // only resort and update if we did change | |
| if (didChange) { | |
| // storeKeys must be a new instance because orderStoreKeys() works on it | |
| if (storeKeys && (storeKeys===oldStoreKeys)) { | |
| storeKeys = storeKeys.copy(); | |
| } | |
| storeKeys = SC.Query.orderStoreKeys(storeKeys, query, store); | |
| if (SC.compare(oldStoreKeys, storeKeys) !== 0){ | |
| this.set('storeKeys', SC.clone(storeKeys)); // replace content | |
| } | |
| } | |
| return this; | |
| }; | |
| SC.RecordArray.prototype.storeDidFetchQuery = function(query) { | |
| if (query.get('isRemote')) this.setIfChanged('status', SC.Record.READY_CLEAN); | |
| return this ; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment