Skip to content

Instantly share code, notes, and snippets.

@mauritslamers
Created January 7, 2016 15:25
Show Gist options
  • Select an option

  • Save mauritslamers/d7c5450642da8be9539e to your computer and use it in GitHub Desktop.

Select an option

Save mauritslamers/d7c5450642da8be9539e to your computer and use it in GitHub Desktop.
Make SC.RecordArray behave conform specifications
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