1 | ;
|
2 | /*!
|
3 | * Copyright 2015 Google Inc. All Rights Reserved.
|
4 | *
|
5 | * Licensed under the Apache License, Version 2.0 (the "License");
|
6 | * you may not use this file except in compliance with the License.
|
7 | * You may obtain a copy of the License at
|
8 | *
|
9 | * http://www.apache.org/licenses/LICENSE-2.0
|
10 | *
|
11 | * Unless required by applicable law or agreed to in writing, software
|
12 | * distributed under the License is distributed on an "AS IS" BASIS,
|
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 | * See the License for the specific language governing permissions and
|
15 | * limitations under the License.
|
16 | */
|
17 | Object.defineProperty(exports, "__esModule", { value: true });
|
18 | exports.ResourceStream = exports.paginator = exports.Paginator = void 0;
|
19 | /*!
|
20 | * @module common/paginator
|
21 | */
|
22 | const arrify = require("arrify");
|
23 | const extend = require("extend");
|
24 | const resource_stream_1 = require("./resource-stream");
|
25 | Object.defineProperty(exports, "ResourceStream", { enumerable: true, get: function () { return resource_stream_1.ResourceStream; } });
|
26 | /*! Developer Documentation
|
27 | *
|
28 | * paginator is used to auto-paginate `nextQuery` methods as well as
|
29 | * streamifying them.
|
30 | *
|
31 | * Before:
|
32 | *
|
33 | * search.query('done=true', function(err, results, nextQuery) {
|
34 | * search.query(nextQuery, function(err, results, nextQuery) {});
|
35 | * });
|
36 | *
|
37 | * After:
|
38 | *
|
39 | * search.query('done=true', function(err, results) {});
|
40 | *
|
41 | * Methods to extend should be written to accept callbacks and return a
|
42 | * `nextQuery`.
|
43 | */
|
44 | class Paginator {
|
45 | /**
|
46 | * Cache the original method, then overwrite it on the Class's prototype.
|
47 | *
|
48 | * @param {function} Class - The parent class of the methods to extend.
|
49 | * @param {string|string[]} methodNames - Name(s) of the methods to extend.
|
50 | */
|
51 | // tslint:disable-next-line:variable-name
|
52 | extend(Class, methodNames) {
|
53 | methodNames = arrify(methodNames);
|
54 | methodNames.forEach(methodName => {
|
55 | const originalMethod = Class.prototype[methodName];
|
56 | // map the original method to a private member
|
57 | Class.prototype[methodName + '_'] = originalMethod;
|
58 | // overwrite the original to auto-paginate
|
59 | /* eslint-disable @typescript-eslint/no-explicit-any */
|
60 | Class.prototype[methodName] = function (...args) {
|
61 | const parsedArguments = paginator.parseArguments_(args);
|
62 | return paginator.run_(parsedArguments, originalMethod.bind(this));
|
63 | };
|
64 | });
|
65 | }
|
66 | /**
|
67 | * Wraps paginated API calls in a readable object stream.
|
68 | *
|
69 | * This method simply calls the nextQuery recursively, emitting results to a
|
70 | * stream. The stream ends when `nextQuery` is null.
|
71 | *
|
72 | * `maxResults` will act as a cap for how many results are fetched and emitted
|
73 | * to the stream.
|
74 | *
|
75 | * @param {string} methodName - Name of the method to streamify.
|
76 | * @return {function} - Wrapped function.
|
77 | */
|
78 | /* eslint-disable @typescript-eslint/no-explicit-any */
|
79 | streamify(methodName) {
|
80 | return function (
|
81 | /* eslint-disable @typescript-eslint/no-explicit-any */
|
82 | ...args) {
|
83 | const parsedArguments = paginator.parseArguments_(args);
|
84 | const originalMethod = this[methodName + '_'] || this[methodName];
|
85 | return paginator.runAsStream_(parsedArguments, originalMethod.bind(this));
|
86 | };
|
87 | }
|
88 | /**
|
89 | * Parse a pseudo-array `arguments` for a query and callback.
|
90 | *
|
91 | * @param {array} args - The original `arguments` pseduo-array that the original
|
92 | * method received.
|
93 | */
|
94 | /* eslint-disable @typescript-eslint/no-explicit-any */
|
95 | parseArguments_(args) {
|
96 | let query;
|
97 | let autoPaginate = true;
|
98 | let maxApiCalls = -1;
|
99 | let maxResults = -1;
|
100 | let callback;
|
101 | const firstArgument = args[0];
|
102 | const lastArgument = args[args.length - 1];
|
103 | if (typeof firstArgument === 'function') {
|
104 | callback = firstArgument;
|
105 | }
|
106 | else {
|
107 | query = firstArgument;
|
108 | }
|
109 | if (typeof lastArgument === 'function') {
|
110 | callback = lastArgument;
|
111 | }
|
112 | if (typeof query === 'object') {
|
113 | query = extend(true, {}, query);
|
114 | // Check if the user only asked for a certain amount of results.
|
115 | if (query.maxResults && typeof query.maxResults === 'number') {
|
116 | // `maxResults` is used API-wide.
|
117 | maxResults = query.maxResults;
|
118 | }
|
119 | else if (typeof query.pageSize === 'number') {
|
120 | // `pageSize` is Pub/Sub's `maxResults`.
|
121 | maxResults = query.pageSize;
|
122 | }
|
123 | if (query.maxApiCalls && typeof query.maxApiCalls === 'number') {
|
124 | maxApiCalls = query.maxApiCalls;
|
125 | delete query.maxApiCalls;
|
126 | }
|
127 | // maxResults is the user specified limit.
|
128 | if (maxResults !== -1 || query.autoPaginate === false) {
|
129 | autoPaginate = false;
|
130 | }
|
131 | }
|
132 | const parsedArguments = {
|
133 | query: query || {},
|
134 | autoPaginate,
|
135 | maxApiCalls,
|
136 | maxResults,
|
137 | callback,
|
138 | };
|
139 | parsedArguments.streamOptions = extend(true, {}, parsedArguments.query);
|
140 | delete parsedArguments.streamOptions.autoPaginate;
|
141 | delete parsedArguments.streamOptions.maxResults;
|
142 | delete parsedArguments.streamOptions.pageSize;
|
143 | return parsedArguments;
|
144 | }
|
145 | /**
|
146 | * This simply checks to see if `autoPaginate` is set or not, if it's true
|
147 | * then we buffer all results, otherwise simply call the original method.
|
148 | *
|
149 | * @param {array} parsedArguments - Parsed arguments from the original method
|
150 | * call.
|
151 | * @param {object=|string=} parsedArguments.query - Query object. This is most
|
152 | * commonly an object, but to make the API more simple, it can also be a
|
153 | * string in some places.
|
154 | * @param {function=} parsedArguments.callback - Callback function.
|
155 | * @param {boolean} parsedArguments.autoPaginate - Auto-pagination enabled.
|
156 | * @param {boolean} parsedArguments.maxApiCalls - Maximum API calls to make.
|
157 | * @param {number} parsedArguments.maxResults - Maximum results to return.
|
158 | * @param {function} originalMethod - The cached method that accepts a callback
|
159 | * and returns `nextQuery` to receive more results.
|
160 | */
|
161 | run_(parsedArguments, originalMethod) {
|
162 | const query = parsedArguments.query;
|
163 | const callback = parsedArguments.callback;
|
164 | if (!parsedArguments.autoPaginate) {
|
165 | return originalMethod(query, callback);
|
166 | }
|
167 | const results = new Array();
|
168 | const promise = new Promise((resolve, reject) => {
|
169 | paginator
|
170 | .runAsStream_(parsedArguments, originalMethod)
|
171 | .on('error', reject)
|
172 | .on('data', (data) => results.push(data))
|
173 | .on('end', () => resolve(results));
|
174 | });
|
175 | if (!callback) {
|
176 | return promise.then(results => [results]);
|
177 | }
|
178 | promise.then(results => callback(null, results), (err) => callback(err));
|
179 | }
|
180 | /**
|
181 | * This method simply calls the nextQuery recursively, emitting results to a
|
182 | * stream. The stream ends when `nextQuery` is null.
|
183 | *
|
184 | * `maxResults` will act as a cap for how many results are fetched and emitted
|
185 | * to the stream.
|
186 | *
|
187 | * @param {object=|string=} parsedArguments.query - Query object. This is most
|
188 | * commonly an object, but to make the API more simple, it can also be a
|
189 | * string in some places.
|
190 | * @param {function=} parsedArguments.callback - Callback function.
|
191 | * @param {boolean} parsedArguments.autoPaginate - Auto-pagination enabled.
|
192 | * @param {boolean} parsedArguments.maxApiCalls - Maximum API calls to make.
|
193 | * @param {number} parsedArguments.maxResults - Maximum results to return.
|
194 | * @param {function} originalMethod - The cached method that accepts a callback
|
195 | * and returns `nextQuery` to receive more results.
|
196 | * @return {stream} - Readable object stream.
|
197 | */
|
198 | /* eslint-disable @typescript-eslint/no-explicit-any */
|
199 | runAsStream_(parsedArguments, originalMethod) {
|
200 | return new resource_stream_1.ResourceStream(parsedArguments, originalMethod);
|
201 | }
|
202 | }
|
203 | exports.Paginator = Paginator;
|
204 | const paginator = new Paginator();
|
205 | exports.paginator = paginator;
|
206 | //# sourceMappingURL=index.js.map |
\ | No newline at end of file |