diff --git a/src/util/make_model.js b/src/util/make_model.js index ecdcd08..a955db6 100644 --- a/src/util/make_model.js +++ b/src/util/make_model.js @@ -40,8 +40,9 @@ export default (options={}) => { upstream_limit: null } - // some random places to make things work + // some random variables to make things work let _xhr = null + let _promise = null // construct the model return { @@ -58,14 +59,20 @@ export default (options={}) => { if (limit == Infinity) limit = _cache.upstream_limit || _cache.count || Infinity - // be lazy: if the data is presented, return the value immediately + // be lazy 1: 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)) + let _portion = _cache.data.slice(offset, offset+limit) + if (_portion.length > 0 && _portion.every(data => data != undefined)) + return Promise.resolve(_portion) + + // be lazy 2: if there is a promise, return it if ambient matches or + // cancel it + if (_promise != null) + return _promise // now the hard work - return _configs.api.request({ + _promise = _configs.api.request({ method: 'GET', url: _configs.endpoint, headers: _cache.count == null ? { @@ -76,34 +83,39 @@ export default (options={}) => { // transform model state to postgest queries //...ambient_queries, offset == 0 ? undefined : {label: 'offset', value: offset}, - limit == Infinity ? undefined : {label: 'limit', value: limit} - ] - }).then(response => { - // 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 - - // 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 + limit == Infinity ? undefined : {label: 'limit', value: limit} + ] + }).then(response => { + // 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 + + // 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 + }) + + // 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.') + + // clean model state + _promise = null + + // return data + return _cache.data.slice(_begin, _end + 1) }) - // 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) - }) + return _promise } } }