1 | ;
|
2 | /*!
|
3 | * Copyright 2014 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.Job = void 0;
|
19 | /*!
|
20 | * @module bigquery/job
|
21 | */
|
22 | const common_1 = require("@google-cloud/common");
|
23 | const paginator_1 = require("@google-cloud/paginator");
|
24 | const promisify_1 = require("@google-cloud/promisify");
|
25 | const extend = require("extend");
|
26 | const bigquery_1 = require("./bigquery");
|
27 | /**
|
28 | * @callback QueryResultsCallback
|
29 | * @param {?Error} err An error returned while making this request.
|
30 | * @param {array} rows The results of the job.
|
31 | */
|
32 | /**
|
33 | * @callback ManualQueryResultsCallback
|
34 | * @param {?Error} err An error returned while making this request.
|
35 | * @param {array} rows The results of the job.
|
36 | * @param {?object} nextQuery A pre-made configuration object for your next
|
37 | * request. This will be `null` if no additional results are available.
|
38 | * If the query is not yet complete, you may get empty `rows` and
|
39 | * non-`null` `nextQuery` that you should use for your next request.
|
40 | * @param {object} apiResponse The full API response.
|
41 | */
|
42 | /**
|
43 | * Job objects are returned from various places in the BigQuery API:
|
44 | *
|
45 | * - {@link BigQuery#getJobs}
|
46 | * - {@link BigQuery#job}
|
47 | * - {@link BigQuery#query}
|
48 | * - {@link BigQuery#createJob}
|
49 | * - {@link Table#copy}
|
50 | * - {@link Table#createWriteStream}
|
51 | * - {@link Table#extract}
|
52 | * - {@link Table#load}
|
53 | *
|
54 | * They can be used to check the status of a running job or fetching the results
|
55 | * of a previously-executed one.
|
56 | *
|
57 | * @class
|
58 | * @param {BigQuery} bigQuery {@link BigQuery} instance.
|
59 | * @param {string} id The ID of the job.
|
60 | * @param {object} [options] Configuration object.
|
61 | * @param {string} [options.location] The geographic location of the job.
|
62 | * Required except for US and EU.
|
63 | *
|
64 | * @example
|
65 | * ```
|
66 | * const {BigQuery} = require('@google-cloud/bigquery');
|
67 | * const bigquery = new BigQuery();
|
68 | *
|
69 | * const job = bigquery.job('job-id');
|
70 | *
|
71 | * //-
|
72 | * // All jobs are event emitters. The status of each job is polled
|
73 | * // continuously, starting only after you register a "complete" listener.
|
74 | * //-
|
75 | * job.on('complete', (metadata) => {
|
76 | * // The job is complete.
|
77 | * });
|
78 | *
|
79 | * //-
|
80 | * // Be sure to register an error handler as well to catch any issues which
|
81 | * // impeded the job.
|
82 | * //-
|
83 | * job.on('error', (err) => {
|
84 | * // An error occurred during the job.
|
85 | * });
|
86 | *
|
87 | * //-
|
88 | * // To force the Job object to stop polling for updates, simply remove any
|
89 | * // "complete" listeners you've registered.
|
90 | * //
|
91 | * // The easiest way to do this is with `removeAllListeners()`.
|
92 | * //-
|
93 | * job.removeAllListeners();
|
94 | * ```
|
95 | */
|
96 | class Job extends common_1.Operation {
|
97 | constructor(bigQuery, id, options) {
|
98 | let location;
|
99 | const methods = {
|
100 | /**
|
101 | * @callback DeleteJobCallback
|
102 | * @param {?Error} err Request error, if any.
|
103 | * @param {object} apiResponse The full API response.
|
104 | */
|
105 | /**
|
106 | * @typedef {array} DeleteJobResponse
|
107 | * @property {object} 0 The full API response.
|
108 | */
|
109 | /**
|
110 | * Delete the job.
|
111 | *
|
112 | * @see [Jobs: delete API Documentation]{@link https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/delete}
|
113 | *
|
114 | * @method Job#delete
|
115 | * @param {DeleteJobCallback} [callback] The callback function.
|
116 | * @param {?error} callback.err An error returned while making this
|
117 | * request.
|
118 | * @param {object} callback.apiResponse The full API response.
|
119 | * @returns {Promise<DeleteJobResponse>}
|
120 | *
|
121 | * @example
|
122 | * const {BigQuery} = require('@google-cloud/bigquery');
|
123 | * const bigquery = new BigQuery();
|
124 | *
|
125 | * const job = bigquery.job(jobId);
|
126 | * job.delete((err, apiResponse) => {
|
127 | * if (!err) {
|
128 | * // The job was deleted successfully.
|
129 | * }
|
130 | * });
|
131 | *
|
132 | * @example If the callback is omitted a Promise will be returned
|
133 | * const [apiResponse] = await job.delete();
|
134 | */
|
135 | delete: {
|
136 | reqOpts: {
|
137 | method: 'DELETE',
|
138 | uri: '/delete',
|
139 | qs: {
|
140 | get location() {
|
141 | return location;
|
142 | },
|
143 | },
|
144 | },
|
145 | },
|
146 | /**
|
147 | * @callback JobExistsCallback
|
148 | * @param {?Error} err Request error, if any.
|
149 | * @param {boolean} exists Indicates if the job exists.
|
150 | */
|
151 | /**
|
152 | * @typedef {array} JobExistsResponse
|
153 | * @property {boolean} 0 Indicates if the job exists.
|
154 | */
|
155 | /**
|
156 | * Check if the job exists.
|
157 | *
|
158 | * @method Job#exists
|
159 | * @param {JobExistsCallback} [callback] The callback function.
|
160 | * @param {?error} callback.err An error returned while making this
|
161 | * request.
|
162 | * @param {boolean} callback.exists Whether the job exists or not.
|
163 | * @returns {Promise<JobExistsResponse>}
|
164 | *
|
165 | * @example
|
166 | * ```
|
167 | * const {BigQuery} = require('@google-cloud/bigquery');
|
168 | * const bigquery = new BigQuery();
|
169 | *
|
170 | * const job = bigquery.job('job-id');
|
171 | *
|
172 | * job.exists((err, exists) => {});
|
173 | *
|
174 | * //-
|
175 | * // If the callback is omitted, we'll return a Promise.
|
176 | * //-
|
177 | * job.exists().then((data) => {
|
178 | * const exists = data[0];
|
179 | * });
|
180 | * ```
|
181 | */
|
182 | exists: true,
|
183 | /**
|
184 | * @callback GetJobCallback
|
185 | * @param {?Error} err Request error, if any.
|
186 | * @param {Model} model The job.
|
187 | * @param {object} apiResponse The full API response body.
|
188 | */
|
189 | /**
|
190 | * @typedef {array} GetJobResponse
|
191 | * @property {Model} 0 The job.
|
192 | * @property {object} 1 The full API response body.
|
193 | */
|
194 | /**
|
195 | * Get a job if it exists.
|
196 | *
|
197 | * @method Job#get
|
198 | * @param {object} [options] Configuration object.
|
199 | * @param {string} [options.location] The geographic location of the job.
|
200 | * Required except for US and EU.
|
201 | * @param {GetJobCallback} [callback] The callback function.
|
202 | * @param {?error} callback.err An error returned while making this
|
203 | * request.
|
204 | * @param {Job} callback.job The job.
|
205 | * @returns {Promise<GetJobResponse>}
|
206 | *
|
207 | * @example
|
208 | * ```
|
209 | * const {BigQuery} = require('@google-cloud/bigquery');
|
210 | * const bigquery = new BigQuery();
|
211 | *
|
212 | * const job = bigquery.job('job-id');
|
213 | *
|
214 | * job.get((err, job, apiResponse) => {
|
215 | * if (!err) {
|
216 | * // `job.metadata` has been populated.
|
217 | * }
|
218 | * });
|
219 | *
|
220 | * //-
|
221 | * // If the callback is omitted, we'll return a Promise.
|
222 | * //-
|
223 | * job.get().then((data) => {
|
224 | * const job = data[0];
|
225 | * const apiResponse = data[1];
|
226 | * });
|
227 | * ```
|
228 | */
|
229 | get: true,
|
230 | /**
|
231 | * @callback GetJobMetadataCallback
|
232 | * @param {?Error} err Request error, if any.
|
233 | * @param {object} metadata The job metadata.
|
234 | * @param {object} apiResponse The full API response.
|
235 | */
|
236 | /**
|
237 | * @typedef {array} GetJobMetadataResponse
|
238 | * @property {object} 0 The job metadata.
|
239 | * @property {object} 1 The full API response.
|
240 | */
|
241 | /**
|
242 | * Get the metadata of the job. This will mostly be useful for checking
|
243 | * the status of a previously-run job.
|
244 | *
|
245 | * See {@link https://cloud.google.com/bigquery/docs/reference/v2/jobs/get| Jobs: get API Documentation}
|
246 | *
|
247 | * @method Job#getMetadata
|
248 | * @param {GetJobMetadataCallback} [callback] The callback function.
|
249 | * @param {?error} callback.err An error returned while making this
|
250 | * request.
|
251 | * @param {object} callback.metadata The metadata of the job.
|
252 | * @param {object} callback.apiResponse The full API response.
|
253 | * @returns {Promise<GetJobMetadataResponse>}
|
254 | *
|
255 | * @example
|
256 | * ```
|
257 | * const {BigQuery} = require('@google-cloud/bigquery');
|
258 | * const bigquery = new BigQuery();
|
259 | *
|
260 | * const job = bigquery.job('id');
|
261 | * job.getMetadata((err, metadata, apiResponse) => {});
|
262 | *
|
263 | * //-
|
264 | * // If the callback is omitted, we'll return a Promise.
|
265 | * //-
|
266 | * job.getMetadata().then((data) => {
|
267 | * const metadata = data[0];
|
268 | * const apiResponse = data[1];
|
269 | * });
|
270 | * ```
|
271 | */
|
272 | getMetadata: {
|
273 | reqOpts: {
|
274 | qs: {
|
275 | get location() {
|
276 | return location;
|
277 | },
|
278 | },
|
279 | },
|
280 | },
|
281 | };
|
282 | super({
|
283 | parent: bigQuery,
|
284 | baseUrl: '/jobs',
|
285 | id,
|
286 | methods,
|
287 | });
|
288 | Object.defineProperty(this, 'location', {
|
289 | get() {
|
290 | return location;
|
291 | },
|
292 | set(_location) {
|
293 | location = _location;
|
294 | },
|
295 | });
|
296 | this.bigQuery = bigQuery;
|
297 | if (options && options.location) {
|
298 | this.location = options.location;
|
299 | }
|
300 | if (options === null || options === void 0 ? void 0 : options.projectId) {
|
301 | this.projectId = options.projectId;
|
302 | }
|
303 | /**
|
304 | * Get the results of a job as a readable object stream.
|
305 | *
|
306 | * @param {object} options Configuration object. See
|
307 | * {@link Job#getQueryResults} for a complete list of options.
|
308 | * @return {stream}
|
309 | *
|
310 | * @example
|
311 | * ```
|
312 | * const through2 = require('through2');
|
313 | * const fs = require('fs');
|
314 | * const {BigQuery} = require('@google-cloud/bigquery');
|
315 | * const bigquery = new BigQuery();
|
316 | *
|
317 | * const job = bigquery.job('job-id');
|
318 | *
|
319 | * job.getQueryResultsStream()
|
320 | * .pipe(through2.obj(function (row, enc, next) {
|
321 | * this.push(JSON.stringify(row) + '\n');
|
322 | * next();
|
323 | * }))
|
324 | * .pipe(fs.createWriteStream('./test/testdata/testfile.json'));
|
325 | * ```
|
326 | */
|
327 | this.getQueryResultsStream = paginator_1.paginator.streamify('getQueryResultsAsStream_');
|
328 | }
|
329 | getQueryResultsStream(options) {
|
330 | // placeholder body, overwritten in constructor
|
331 | return new paginator_1.ResourceStream({}, () => { });
|
332 | }
|
333 | cancel(callback) {
|
334 | let qs;
|
335 | if (this.location) {
|
336 | qs = { location: this.location };
|
337 | }
|
338 | this.request({
|
339 | method: 'POST',
|
340 | uri: '/cancel',
|
341 | qs,
|
342 | }, callback);
|
343 | }
|
344 | getQueryResults(optionsOrCallback, cb) {
|
345 | const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
|
346 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
347 | const qs = extend({
|
348 | location: this.location,
|
349 | }, options);
|
350 | const wrapIntegers = qs.wrapIntegers ? qs.wrapIntegers : false;
|
351 | delete qs.wrapIntegers;
|
352 | delete qs.job;
|
353 | const timeoutOverride = typeof qs.timeoutMs === 'number' ? qs.timeoutMs : false;
|
354 | this.bigQuery.request({
|
355 | uri: '/queries/' + this.id,
|
356 | qs,
|
357 | }, (err, resp) => {
|
358 | if (err) {
|
359 | callback(err, null, null, resp);
|
360 | return;
|
361 | }
|
362 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
363 | let rows = [];
|
364 | if (resp.schema && resp.rows) {
|
365 | rows = bigquery_1.BigQuery.mergeSchemaWithRows_(resp.schema, resp.rows, wrapIntegers);
|
366 | }
|
367 | let nextQuery = null;
|
368 | if (resp.jobComplete === false) {
|
369 | // Query is still running.
|
370 | nextQuery = Object.assign({}, options);
|
371 | // If timeout override was provided, return error.
|
372 | if (timeoutOverride) {
|
373 | const err = new Error(`The query did not complete before ${timeoutOverride}ms`);
|
374 | callback(err, null, nextQuery, resp);
|
375 | return;
|
376 | }
|
377 | }
|
378 | else if (resp.pageToken) {
|
379 | // More results exist.
|
380 | nextQuery = Object.assign({}, options, {
|
381 | pageToken: resp.pageToken,
|
382 | });
|
383 | }
|
384 | callback(null, rows, nextQuery, resp);
|
385 | });
|
386 | }
|
387 | /**
|
388 | * This method will be called by `getQueryResultsStream()`. It is required to
|
389 | * properly set the `autoPaginate` option value.
|
390 | *
|
391 | * @private
|
392 | */
|
393 | getQueryResultsAsStream_(options, callback) {
|
394 | options = extend({ autoPaginate: false }, options);
|
395 | this.getQueryResults(options, callback);
|
396 | }
|
397 | /**
|
398 | * Poll for a status update. Execute the callback:
|
399 | *
|
400 | * - callback(err): Job failed
|
401 | * - callback(): Job incomplete
|
402 | * - callback(null, metadata): Job complete
|
403 | *
|
404 | * @private
|
405 | *
|
406 | * @param {function} callback
|
407 | */
|
408 | poll_(callback) {
|
409 | this.getMetadata((err, metadata) => {
|
410 | if (!err && metadata.status && metadata.status.errorResult) {
|
411 | err = new common_1.util.ApiError(metadata.status);
|
412 | }
|
413 | if (err) {
|
414 | callback(err);
|
415 | return;
|
416 | }
|
417 | if (metadata.status.state !== 'DONE') {
|
418 | callback(null);
|
419 | return;
|
420 | }
|
421 | callback(null, metadata);
|
422 | });
|
423 | }
|
424 | }
|
425 | exports.Job = Job;
|
426 | /*! Developer Documentation
|
427 | *
|
428 | * These methods can be auto-paginated.
|
429 | */
|
430 | paginator_1.paginator.extend(Job, ['getQueryResults']);
|
431 | /*! Developer Documentation
|
432 | *
|
433 | * All async methods (except for streams) will return a Promise in the event
|
434 | * that a callback is omitted.
|
435 | */
|
436 | promisify_1.promisifyAll(Job);
|
437 | //# sourceMappingURL=job.js.map |
\ | No newline at end of file |