📄 resultset.js
字号:
getServerFilter : function () { // local mode: no server-side filtering if (this.isLocal()) return null; return this.criteria;},// clear the fetch timer and explicitly pass start and end row to provide a clean entry point// for the overrideable fetchRemoteData_fetchRemoteData : function () { var startRow = this.fetchStartRow, endRow = this.fetchEndRow; // this indicates that a timer was set to do a fetch, but then an immediate fetch (no fetch // delay) occurred if (startRow == null || endRow == null) return; // now that we're definitely going to fetch the data, insert loading markers into the local // cache so that we don't issue fetch requests on any rows we're already fetching. this.setRangeLoading(startRow, endRow); this.fetchStartRow = null; this.fetchEndRow = null; //>DEBUG this.logInfo("fetching rows " + [startRow, endRow] + " from server"); //<DEBUG return this.fetchRemoteData(this.getServerFilter(), startRow, endRow);},//> @method resultSet.fetchRemoteData() [A]// Retrieve a range of rows from the server.// <P>// Override to provide your own implementation of data retrieval. Use fillCacheData() and// setFullLength() to manipulate the cache once rows are retrieved.// <P>// Implementer is expected to return <b>all</b> requested rows. fetchRemoteData() may ask for// more rows than the current totalRows; if not enough rows are available, setFullLength()// should be called to trim to the appropriate size.// // @see setFullLength()// @see fillCacheData()//// @param serverCriteria (Criteria) criteria to be applied by server// @param startRow (number) startRow position// @param endRow (number) endRow position// @visibility customResultSet//<_requestIndex:0,fetchRemoteData : function (serverCriteria, startRow, endRow) { //>Offline if (isc.isOffline()) { // save a marker that we have offline records so we can invalidateCache() when // we go online this.haveOfflineRecords = true; return; } //<Offline this._requestIndex += 1; var clientContext; if (this.context && this.context.clientContext) { this.context.clientContext.requestIndex = this._requestIndex; } else { clientContext = {requestIndex: this._requestIndex}; } var requestProperties = isc.addProperties({ operation : this.getOperationId("fetch"), startRow : startRow, endRow : endRow, sortBy : this._serverSortBy, resultSet : this, clientContext : clientContext, // so that we don't get wedged in a loading state willHandleError:true }, this.context) // if cache was partially updated before, invalidate the cache if (this.rowOrderInvalid()) { this.logInfo("invalidating rows on fetch due to 'add'/'update' operation " + " with updatePartialCache"); this.invalidateRows(); } this.getDataSource().fetchData(serverCriteria, {caller:this, methodName:"fetchRemoteDataReply"}, requestProperties); // For local filtering, we fetch every row in the dataSet once (and filter the results) // for basic filtering we re-fetch when criteria change. // In either case the total number of rows that match the filter criteria will be unknown // until the fetch returns. // This differs from paged resultSets where we track total size via the totalLength // flag (and a fetch doesn't necessarily mean a complete dataSet refresh). // Set a flag so lengthIsKnown() can detect when we're loading rows. if (!this.isPaged()) this._fetchingRequest = this._requestIndex; },fetchRemoteDataReply : function (dsResponse, data, request) { var index = dsResponse.clientContext.requestIndex; if (!this._lastProcessedResponse) this._lastProcessedResponse = 0; if (index != (this._lastProcessedResponse+1)) { this.logInfo("server returned out-of-sequence response for fetch remote data request " + " - delaying processing: last processed:"+ this._lastProcessedResponse + ", returned:"+ index); if (!this._outOfSequenceResponses) this._outOfSequenceResponses = []; this._outOfSequenceResponses.add({dsResponse:dsResponse, data:data, request:request}); return; } // Clear the fetchingRequest flag if we're a non-paged resultSet if (!this.isPaged() && this._fetchingRequest == index) delete this._fetchingRequest; var newData; // if the fetch failed, clear our 'loading' marker, and then send over to RPCManager // to do normal error handling if (dsResponse.status < 0 || dsResponse.offlineResponse) { newData = []; } else { newData = dsResponse.data } var numResults = newData.length; this.document = dsResponse.document; //>DEBUG this.logInfo("Received " + numResults + " records from server"); //<DEBUG // if the server did not specify startRow, assume startRow is what // was asked for if (dsResponse.startRow == null) dsResponse.startRow = request.startRow; // if the server did not specify an endRow, assume endRow is startRow + number of // records returned. if (dsResponse.endRow == null) dsResponse.endRow = dsResponse.startRow + numResults; // if the server did not specify totalRows, but the resulting endRow is less than what we // asked for, then we know the server has no more rows, clamp totalRows to endRow if (dsResponse.totalRows == null && dsResponse.endRow < request.endRow) dsResponse.totalRows = dsResponse.endRow; // opportunity to transform data from the server if (this.transformData) { var result = this.transformData(newData, dsResponse); // handle failure to return the untransformed data newData = result != null ? result : newData; if (newData.length != numResults) { this.logInfo("Transform applied, " + newData.length + " records resulted, from " + dsResponse.startRow + " to " + dsResponse.endRow); // update endRow dsResponse.endRow = dsResponse.startRow + newData.length; // totalRows may also need to be adjusted here, but just fall through to the generic // clamp below } } if (!isc.isA.List(newData)) { this.logWarn("Bad data returned, ignoring: " + this.echo(newData)); return; } // If the server returned an endRow past the end of the list, warn and clamp // dsResponse.endRow to the end of the list so dataArrived etc are passed the correct // info on the last loaded row if (dsResponse.totalRows != null && dsResponse.totalRows < dsResponse.endRow) { this.logWarn("fetchData callback: dsResponse.endRow set to:" + dsResponse.endRow + ". dsResponse.totalRows set to:" + dsResponse.totalRows + ". endRow cannot exceed total dataset size. " + "Clamping endRow to the end of the dataset (" + dsResponse.totalRows + ")."); dsResponse.endRow = dsResponse.totalRows; } // NOTE: transformData is allowed to modify results.startRow/endRow/totalRows var startRow = dsResponse.startRow, endRow = dsResponse.endRow; this._startDataArriving(); // incorporate new data into the cache this._handleNewData(newData, dsResponse); this._doneDataArriving(); delete this.context.afterFlowCallback; this._lastProcessedResponse = index; if (this._outOfSequenceResponses && this._outOfSequenceResponses.length > 0) { for (var i = 0; i < this._outOfSequenceResponses.length; i++) { var reply = this._outOfSequenceResponses[i]; if (reply == null) continue; var requestIndex = reply.dsResponse.clientContext.requestIndex; if (requestIndex == this._lastProcessedResponse +1) { this.logInfo("Delayed out of sequence data response being processed now " + requestIndex); this._outOfSequenceResponses[i] = null; this.fetchRemoteDataReply(reply.dsResponse, reply.data, reply.request); break; } } } if (dsResponse.status < 0) { isc.RPCManager._handleError(dsResponse, request) }}, _handleNewData : function (newData, result) { if (this.isLocal()) { // when we get the complete dataset from the server we hold onto it as "allRows" and // set this.localData to a locally filtered subset this.allRows = newData; this.filterLocalData(); return; } else if (!this.isPaged()) { this._startChangingData(); this.localData = newData; if (this.canSortOnClient()) { // if client sorting is allowed, sort locally, so that the server does not have to // send sorted records and sorting doesn't have to match between client and server this._doSort(); } // If our criteria is empty, we have all rows cached - in this case store this.allRows // so we can perform a local filter on a call to 'setCriteria'. NOTE: done within // fillCacheData for a paged ResultSet if (this.allRowsCached()) { this.allRows = this.localData; } this._doneChangingData(); return; } // paged mode var context = result.context; this._startChangingData() // crude staleness detection: change in totalRows if (this.dropCacheOnLengthChange && this.lengthIsKnown() && this.totalRows != result.totalRows) { //>DEBUG this.logInfo("totalRows changed from " + this.totalRows + " to " + result.totalRows + ", invalidating cache"); //<DEBUG this._invalidateCache(); // NOTE: doesn't trigger observers yet } // initialize the cache if we've never loaded rows before if (this.localData == null) this.localData = []; // trimming length discards any "LOADING" marker rows for rows that don't exist on the // server this.setFullLength(result.totalRows); // add the rows to our cache this.fillCacheData(newData, result.startRow); // handle server batch size set too small: clear loading markers for the rest of the // requested range so that new requests will be fired. NOTE: the true fix is to make // client and server batch size agree, because if multiple concurrent requests are // outstanding, there is a bad case where one request comes back and clears loading markers // set by another request, causing a third request to be initiated for rows already being // fetched. var localData = this.localData; for (var i = result.startRow + newData.length; i < this.totalRows; i++) { if (Array.isLoading(localData[i])) localData[i] = null; } //>DEBUG this.logInfo("cached " + newData.getLength() + " rows, from " + result.startRow + " to " + result.endRow + " (" + this.totalRows + " total rows, " + this.cachedRows + " cached)"); //<DEBUG if (this.allMatchingRowsCached()) { if (this.allRowsCached()) { this.logInfo("Cache for entire DataSource complete"); } else { this.logInfo("Cache for current criteria complete"); } // sort, because if we just completed a dataset where we had a partial cache before, // then the data was previously in a sort order specified by the server if (this.canSortOnClient()) this._doSort(); } // call dataChanged in case anyone is observing it this._doneChangingData();},setContext : function (context) { this.context = context;},
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -