diff --git a/src/util/make_model.js b/src/util/make_model.js index 111e9e4..5db027a 100644 --- a/src/util/make_model.js +++ b/src/util/make_model.js @@ -36,7 +36,8 @@ export default (options={}) => { // private model cache & meta-info let _cache = { data: null, - count: null + count: null, + upstream_limit: null } // some random places to make things work @@ -49,10 +50,20 @@ export default (options={}) => { cache() { return _cache }, // main methods - select(from=0, to) { + select(offset=0, limit=Infinity) { // initialize data (singular or plural) _cache.data = _cache.data || [] + // normalize limit + if (limit == Infinity) + limit = _cache.upstream_limit || _cache.count || Infinity + + // be lazy: if the data is presented, return the value immediately + // + // note that Array.every(list) == true if list is empty + if (_cache.data.slice(offset, offset+limit).length > 0 && _cache.data.slice(offset, offset+limit).every(data => data != undefined)) + return Promise.resolve(_cache.data.slice(offset, offset+limit)) + // now the hard work return _configs.api.request({ method: 'GET', @@ -65,20 +76,29 @@ export default (options={}) => { // transform model state to postgest queries //queries: [...ambient_queries, ...paging_queries] }).then(response => { - // gather begin/end/count - let [_range, _count] = _xhr.getResponseHeader('content-range').split('/') - let [_begin, _end] = _range.split('-').map(v => ~~v) + // gather begin/end/count + let [_range, _count] = _xhr.getResponseHeader('content-range').split('/') + let [_begin, _end] = _range.split('-').map(v => ~~v) + + // update count if presented + if (_count != '*') _cache.count = _count - // update count if presented - if (_count != '*') _cache.count = _count + // see if an upstream limit is exposed + if (_end - _begin + 1 < limit) _cache.upstream_limit = _end - _begin + 1 - // fill the data cache - response.forEach((data, i) => { - // _value_filters.forEach(([label, config]) => data[config.alias || label] = config.value_filter(data[config.alias || label])) - _cache.data[_begin + i] = data - }) + // fill the data cache + response.forEach((data, i) => { + // _value_filters.forEach(([label, config]) => data[config.alias || label] = config.value_filter(data[config.alias || label])) + _cache.data[_begin + i] = data + }) - // for promise + // assert offset/limit and returned range + if (offset != _begin || _end - _begin + 1 > limit) + throw 'The request and response data range mismatches!' + if (_end - _begin + 1 < limit) + console.warn('The response range is narrower than requested, probably due to an upstream hard limit.') + + // return return _cache.data.slice(_begin, _end + 1) }) } @@ -100,10 +120,7 @@ export const default1 = (args) => { return { // model & model state - list: [], - count: null, fully_loaded: false, - xhr: null, // ambient ambient: null, @@ -134,14 +151,8 @@ export const default1 = (args) => { // load data load(args) { - args = args || {begin: 0} - let ambient_queries = this.reset() - // be lazy: if the data is presented, return the value immediately - if (this.list.slice(args.begin, args.end).length == args.limit && this.list.slice(args.begin, args.end).every(data => data != undefined)) - return Promise.resolve(this.list.slice(args.begin, args.end)) - // create limit&offset for postgrest let paging_queries = [] if (args.begin != undefined) {