1 | ;
|
2 | /*!
|
3 | * Copyright 2019 Google LLC
|
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.BigQueryInt = exports.BigQueryTime = exports.BigQueryDatetime = exports.BigQueryTimestamp = exports.Geography = exports.BigQueryDate = exports.BigQuery = exports.PROTOCOL_REGEX = void 0;
|
19 | const common_1 = require("@google-cloud/common");
|
20 | const paginator_1 = require("@google-cloud/paginator");
|
21 | const promisify_1 = require("@google-cloud/promisify");
|
22 | const arrify = require("arrify");
|
23 | const big_js_1 = require("big.js");
|
24 | const extend = require("extend");
|
25 | const is = require("is");
|
26 | const uuid = require("uuid");
|
27 | const dataset_1 = require("./dataset");
|
28 | const job_1 = require("./job");
|
29 | const table_1 = require("./table");
|
30 | exports.PROTOCOL_REGEX = /^(\w*):\/\//;
|
31 | /**
|
32 | * @typedef {object} BigQueryOptions
|
33 | * @property {string} [projectId] The project ID from the Google Developer's
|
34 | * Console, e.g. 'grape-spaceship-123'. We will also check the environment
|
35 | * variable `GCLOUD_PROJECT` for your project ID. If your app is running in
|
36 | * an environment which supports {@link
|
37 | * https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
|
38 | * Application Default Credentials}, your project ID will be detected
|
39 | * automatically.
|
40 | * @property {string} [keyFilename] Full path to the a .json, .pem, or .p12 key
|
41 | * downloaded from the Google Developers Console. If you provide a path to a
|
42 | * JSON file, the `projectId` option above is not necessary. NOTE: .pem and
|
43 | * .p12 require you to specify the `email` option as well.
|
44 | * @property {string} [token] An OAUTH access token. If provided, we will not
|
45 | * manage fetching, re-using, and re-minting access tokens.
|
46 | * @property {string} [email] Account email address. Required when using a .pem
|
47 | * or .p12 keyFilename.
|
48 | * @property {object} [credentials] Credentials object.
|
49 | * @property {string} [credentials.client_email]
|
50 | * @property {string} [credentials.private_key]
|
51 | * @property {Constructor} [promise] Custom promise module to use instead of
|
52 | * native Promises.
|
53 | * @property {string[]} [scopes] Additional OAuth scopes to use in requests. For
|
54 | * example, to access an external data source, you may need the
|
55 | * `https://www.googleapis.com/auth/drive.readonly` scope.
|
56 | */
|
57 | /**
|
58 | * In the following examples from this page and the other modules (`Dataset`,
|
59 | * `Table`, etc.), we are going to be using a dataset from
|
60 | * {@link http://goo.gl/f2SXcb| data.gov} of higher education institutions.
|
61 | *
|
62 | * We will create a table with the correct schema, import the public CSV file
|
63 | * into that table, and query it for data.
|
64 | *
|
65 | * @class
|
66 | *
|
67 | * See {@link https://cloud.google.com/bigquery/what-is-bigquery| What is BigQuery?}
|
68 | *
|
69 | * @param {BigQueryOptions} options Constructor options.
|
70 | *
|
71 | * @example Install the client library with <a href="https://www.npmjs.com/">npm</a>:
|
72 | * ```
|
73 | * npm install @google-cloud/bigquery
|
74 | *
|
75 | * ```
|
76 | * @example Import the client library
|
77 | * ```
|
78 | * const {BigQuery} = require('@google-cloud/bigquery');
|
79 | *
|
80 | * ```
|
81 | * @example Create a client that uses <a href="https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application">Application Default Credentials (ADC)</a>:
|
82 | * ```
|
83 | * const bigquery = new BigQuery();
|
84 | *
|
85 | * ```
|
86 | * @example Create a client with <a href="https://cloud.google.com/docs/authentication/production#obtaining_and_providing_service_account_credentials_manually">explicit credentials</a>:
|
87 | * ```
|
88 | * const bigquery = new BigQuery({
|
89 | * projectId: 'your-project-id',
|
90 | * keyFilename: '/path/to/keyfile.json'
|
91 | * });
|
92 | *
|
93 | * ```
|
94 | * @example <caption>include:samples/quickstart.js</caption>
|
95 | * region_tag:bigquery_quickstart
|
96 | * Full quickstart example:
|
97 | */
|
98 | class BigQuery extends common_1.Service {
|
99 | createQueryStream(options) {
|
100 | // placeholder body, overwritten in constructor
|
101 | return new paginator_1.ResourceStream({}, () => { });
|
102 | }
|
103 | getDatasetsStream(options) {
|
104 | // placeholder body, overwritten in constructor
|
105 | return new paginator_1.ResourceStream({}, () => { });
|
106 | }
|
107 | getJobsStream(options) {
|
108 | // placeholder body, overwritten in constructor
|
109 | return new paginator_1.ResourceStream({}, () => { });
|
110 | }
|
111 | constructor(options = {}) {
|
112 | let apiEndpoint = 'https://bigquery.googleapis.com';
|
113 | const EMULATOR_HOST = process.env.BIGQUERY_EMULATOR_HOST;
|
114 | if (typeof EMULATOR_HOST === 'string') {
|
115 | apiEndpoint = BigQuery.sanitizeEndpoint(EMULATOR_HOST);
|
116 | }
|
117 | if (options.apiEndpoint) {
|
118 | apiEndpoint = BigQuery.sanitizeEndpoint(options.apiEndpoint);
|
119 | }
|
120 | options = Object.assign({}, options, {
|
121 | apiEndpoint,
|
122 | });
|
123 | const baseUrl = EMULATOR_HOST || `${options.apiEndpoint}/bigquery/v2`;
|
124 | const config = {
|
125 | apiEndpoint: options.apiEndpoint,
|
126 | baseUrl,
|
127 | scopes: ['https://www.googleapis.com/auth/bigquery'],
|
128 | packageJson: require('../../package.json'),
|
129 | autoRetry: options.autoRetry,
|
130 | maxRetries: options.maxRetries,
|
131 | };
|
132 | if (options.scopes) {
|
133 | config.scopes = config.scopes.concat(options.scopes);
|
134 | }
|
135 | super(config, options);
|
136 | this.location = options.location;
|
137 | /**
|
138 | * Run a query scoped to your project as a readable object stream.
|
139 | *
|
140 | * @method
|
141 | * @param {object} query Configuration object. See {@link BigQuery.query} for a complete
|
142 | * list of options.
|
143 | *
|
144 | * @example
|
145 | * ```
|
146 | * const {BigQuery} = require('@google-cloud/bigquery');
|
147 | * const bigquery = new BigQuery();
|
148 | *
|
149 | * const query = 'SELECT url FROM `publicdata.samples.github_nested` LIMIT
|
150 | * 100';
|
151 | *
|
152 | * bigquery.createQueryStream(query)
|
153 | * .on('error', console.error)
|
154 | * .on('data', function(row) {
|
155 | * // row is a result from your query.
|
156 | * })
|
157 | * .on('end', function() {
|
158 | * // All rows retrieved.
|
159 | * });
|
160 | *
|
161 | * //-
|
162 | * // If you anticipate many results, you can end a stream early to prevent
|
163 | * // unnecessary processing and API requests.
|
164 | * //-
|
165 | * bigquery.createQueryStream(query)
|
166 | * .on('data', function(row) {
|
167 | * this.end();
|
168 | * });
|
169 | * ```
|
170 | */
|
171 | this.createQueryStream = paginator_1.paginator.streamify('queryAsStream_');
|
172 | /**
|
173 | * List all or some of the {@link Dataset} objects in your project as
|
174 | * a readable object stream.
|
175 | *
|
176 | * @param {object} [options] Configuration object. See
|
177 | * {@link BigQuery.getDatasets} for a complete list of options.
|
178 | *
|
179 | * @example
|
180 | * ```
|
181 | * const {BigQuery} = require('@google-cloud/bigquery');
|
182 | * const bigquery = new BigQuery();
|
183 | *
|
184 | * bigquery.getDatasetsStream()
|
185 | * .on('error', console.error)
|
186 | * .on('data', function(dataset) {
|
187 | * // dataset is a Dataset object.
|
188 | * })
|
189 | * .on('end', function() {
|
190 | * // All datasets retrieved.
|
191 | * });
|
192 | *
|
193 | * //-
|
194 | * // If you anticipate many results, you can end a stream early to prevent
|
195 | * // unnecessary processing and API requests.
|
196 | * //-
|
197 | * bigquery.getDatasetsStream()
|
198 | * .on('data', function(dataset) {
|
199 | * this.end();
|
200 | * });
|
201 | * ```
|
202 | */
|
203 | this.getDatasetsStream = paginator_1.paginator.streamify('getDatasets');
|
204 | /**
|
205 | * List all or some of the {@link Job} objects in your project as a
|
206 | * readable object stream.
|
207 | *
|
208 | * @param {object} [options] Configuration object. See
|
209 | * {@link BigQuery.getJobs} for a complete list of options.
|
210 | *
|
211 | * @example
|
212 | * ```
|
213 | * const {BigQuery} = require('@google-cloud/bigquery');
|
214 | * const bigquery = new BigQuery();
|
215 | *
|
216 | * bigquery.getJobsStream()
|
217 | * .on('error', console.error)
|
218 | * .on('data', function(job) {
|
219 | * // job is a Job object.
|
220 | * })
|
221 | * .on('end', function() {
|
222 | * // All jobs retrieved.
|
223 | * });
|
224 | *
|
225 | * //-
|
226 | * // If you anticipate many results, you can end a stream early to prevent
|
227 | * // unnecessary processing and API requests.
|
228 | * //-
|
229 | * bigquery.getJobsStream()
|
230 | * .on('data', function(job) {
|
231 | * this.end();
|
232 | * });
|
233 | * ```
|
234 | */
|
235 | this.getJobsStream = paginator_1.paginator.streamify('getJobs');
|
236 | // Disable `prettyPrint` for better performance.
|
237 | // https://github.com/googleapis/nodejs-bigquery/issues/858
|
238 | this.interceptors.push({
|
239 | request: (reqOpts) => {
|
240 | return extend(true, {}, reqOpts, { qs: { prettyPrint: false } });
|
241 | },
|
242 | });
|
243 | }
|
244 | static sanitizeEndpoint(url) {
|
245 | if (!exports.PROTOCOL_REGEX.test(url)) {
|
246 | url = `https://${url}`;
|
247 | }
|
248 | return url.replace(/\/+$/, ''); // Remove trailing slashes
|
249 | }
|
250 | /**
|
251 | * Merge a rowset returned from the API with a table schema.
|
252 | *
|
253 | * @private
|
254 | *
|
255 | * @param {object} schema
|
256 | * @param {array} rows
|
257 | * @param {boolean|IntegerTypeCastOptions} wrapIntegers Wrap values of
|
258 | * 'INT64' type in {@link BigQueryInt} objects.
|
259 | * If a `boolean`, this will wrap values in {@link BigQueryInt} objects.
|
260 | * If an `object`, this will return a value returned by
|
261 | * `wrapIntegers.integerTypeCastFunction`.
|
262 | * Please see {@link IntegerTypeCastOptions} for options descriptions.
|
263 | * @param {array} selectedFields List of fields to return.
|
264 | * If unspecified, all fields are returned.
|
265 | * @returns Fields using their matching names from the table's schema.
|
266 | */
|
267 | static mergeSchemaWithRows_(schema, rows, wrapIntegers, selectedFields) {
|
268 | var _a;
|
269 | if (selectedFields && selectedFields.length > 0) {
|
270 | const selectedFieldsArray = selectedFields.map(c => {
|
271 | return c.split('.');
|
272 | });
|
273 | const currentFields = selectedFieldsArray.map(c => c.shift());
|
274 | //filter schema fields based on selected fields.
|
275 | schema.fields = (_a = schema.fields) === null || _a === void 0 ? void 0 : _a.filter(field => currentFields
|
276 | .map(c => c.toLowerCase())
|
277 | .indexOf(field.name.toLowerCase()) >= 0);
|
278 | selectedFields = selectedFieldsArray
|
279 | .filter(c => c.length > 0)
|
280 | .map(c => c.join('.'));
|
281 | }
|
282 | return arrify(rows)
|
283 | .map(mergeSchema)
|
284 | .map(flattenRows);
|
285 | function mergeSchema(row) {
|
286 | return row.f.map((field, index) => {
|
287 | const schemaField = schema.fields[index];
|
288 | let value = field.v;
|
289 | if (schemaField.mode === 'REPEATED') {
|
290 | value = value.map(val => {
|
291 | return convert(schemaField, val.v, wrapIntegers, selectedFields);
|
292 | });
|
293 | }
|
294 | else {
|
295 | value = convert(schemaField, value, wrapIntegers, selectedFields);
|
296 | }
|
297 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
298 | const fieldObject = {};
|
299 | fieldObject[schemaField.name] = value;
|
300 | return fieldObject;
|
301 | });
|
302 | }
|
303 | function convert(schemaField,
|
304 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
305 | value, wrapIntegers, selectedFields) {
|
306 | if (is.null(value)) {
|
307 | return value;
|
308 | }
|
309 | switch (schemaField.type) {
|
310 | case 'BOOLEAN':
|
311 | case 'BOOL': {
|
312 | value = value.toLowerCase() === 'true';
|
313 | break;
|
314 | }
|
315 | case 'BYTES': {
|
316 | value = Buffer.from(value, 'base64');
|
317 | break;
|
318 | }
|
319 | case 'FLOAT':
|
320 | case 'FLOAT64': {
|
321 | value = Number(value);
|
322 | break;
|
323 | }
|
324 | case 'INTEGER':
|
325 | case 'INT64': {
|
326 | value = wrapIntegers
|
327 | ? typeof wrapIntegers === 'object'
|
328 | ? BigQuery.int({ integerValue: value, schemaFieldName: schemaField.name }, wrapIntegers).valueOf()
|
329 | : BigQuery.int(value)
|
330 | : Number(value);
|
331 | break;
|
332 | }
|
333 | case 'NUMERIC': {
|
334 | value = new big_js_1.Big(value);
|
335 | break;
|
336 | }
|
337 | case 'BIGNUMERIC': {
|
338 | value = new big_js_1.Big(value);
|
339 | break;
|
340 | }
|
341 | case 'RECORD': {
|
342 | value = BigQuery.mergeSchemaWithRows_(schemaField, value, wrapIntegers, selectedFields).pop();
|
343 | break;
|
344 | }
|
345 | case 'DATE': {
|
346 | value = BigQuery.date(value);
|
347 | break;
|
348 | }
|
349 | case 'DATETIME': {
|
350 | value = BigQuery.datetime(value);
|
351 | break;
|
352 | }
|
353 | case 'TIME': {
|
354 | value = BigQuery.time(value);
|
355 | break;
|
356 | }
|
357 | case 'TIMESTAMP': {
|
358 | value = BigQuery.timestamp(new Date(value * 1000));
|
359 | break;
|
360 | }
|
361 | case 'GEOGRAPHY': {
|
362 | value = BigQuery.geography(value);
|
363 | break;
|
364 | }
|
365 | default:
|
366 | break;
|
367 | }
|
368 | return value;
|
369 | }
|
370 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
371 | function flattenRows(rows) {
|
372 | return rows.reduce((acc, row) => {
|
373 | const key = Object.keys(row)[0];
|
374 | acc[key] = row[key];
|
375 | return acc;
|
376 | }, {});
|
377 | }
|
378 | }
|
379 | /**
|
380 | * The `DATE` type represents a logical calendar date, independent of time
|
381 | * zone. It does not represent a specific 24-hour time period. Rather, a given
|
382 | * DATE value represents a different 24-hour period when interpreted in
|
383 | * different time zones, and may represent a shorter or longer day during
|
384 | * Daylight Savings Time transitions.
|
385 | *
|
386 | * @param {object|string} value The date. If a string, this should be in the
|
387 | * format the API describes: `YYYY-[M]M-[D]D`.
|
388 | * Otherwise, provide an object.
|
389 | * @param {string|number} value.year Four digits.
|
390 | * @param {string|number} value.month One or two digits.
|
391 | * @param {string|number} value.day One or two digits.
|
392 | *
|
393 | * @example
|
394 | * ```
|
395 | * const {BigQuery} = require('@google-cloud/bigquery');
|
396 | * const bigquery = new BigQuery();
|
397 | * const date = bigquery.date('2017-01-01');
|
398 | *
|
399 | * //-
|
400 | * // Alternatively, provide an object.
|
401 | * //-
|
402 | * const date2 = bigquery.date({
|
403 | * year: 2017,
|
404 | * month: 1,
|
405 | * day: 1
|
406 | * });
|
407 | * ```
|
408 | */
|
409 | static date(value) {
|
410 | return new BigQueryDate(value);
|
411 | }
|
412 | /**
|
413 | * @param {object|string} value The date. If a string, this should be in the
|
414 | * format the API describes: `YYYY-[M]M-[D]D`.
|
415 | * Otherwise, provide an object.
|
416 | * @param {string|number} value.year Four digits.
|
417 | * @param {string|number} value.month One or two digits.
|
418 | * @param {string|number} value.day One or two digits.
|
419 | *
|
420 | * @example
|
421 | * ```
|
422 | * const {BigQuery} = require('@google-cloud/bigquery');
|
423 | * const date = BigQuery.date('2017-01-01');
|
424 | *
|
425 | * //-
|
426 | * // Alternatively, provide an object.
|
427 | * //-
|
428 | * const date2 = BigQuery.date({
|
429 | * year: 2017,
|
430 | * month: 1,
|
431 | * day: 1
|
432 | * });
|
433 | * ```
|
434 | */
|
435 | date(value) {
|
436 | return BigQuery.date(value);
|
437 | }
|
438 | /**
|
439 | * A `DATETIME` data type represents a point in time. Unlike a `TIMESTAMP`,
|
440 | * this does not refer to an absolute instance in time. Instead, it is the
|
441 | * civil time, or the time that a user would see on a watch or calendar.
|
442 | *
|
443 | * @method BigQuery.datetime
|
444 | * @param {object|string} value The time. If a string, this should be in the
|
445 | * format the API describes: `YYYY-[M]M-[D]D[ [H]H:[M]M:[S]S[.DDDDDD]]`.
|
446 | * Otherwise, provide an object.
|
447 | * @param {string|number} value.year Four digits.
|
448 | * @param {string|number} value.month One or two digits.
|
449 | * @param {string|number} value.day One or two digits.
|
450 | * @param {string|number} [value.hours] One or two digits (`00` - `23`).
|
451 | * @param {string|number} [value.minutes] One or two digits (`00` - `59`).
|
452 | * @param {string|number} [value.seconds] One or two digits (`00` - `59`).
|
453 | * @param {string|number} [value.fractional] Up to six digits for microsecond
|
454 | * precision.
|
455 | *
|
456 | * @example
|
457 | * ```
|
458 | * const {BigQuery} = require('@google-cloud/bigquery');
|
459 | * const datetime = BigQuery.datetime('2017-01-01 13:00:00');
|
460 | *
|
461 | * //-
|
462 | * // Alternatively, provide an object.
|
463 | * //-
|
464 | * const datetime = BigQuery.datetime({
|
465 | * year: 2017,
|
466 | * month: 1,
|
467 | * day: 1,
|
468 | * hours: 14,
|
469 | * minutes: 0,
|
470 | * seconds: 0
|
471 | * });
|
472 | * ```
|
473 | */
|
474 | /**
|
475 | * A `DATETIME` data type represents a point in time. Unlike a `TIMESTAMP`,
|
476 | * this does not refer to an absolute instance in time. Instead, it is the
|
477 | * civil time, or the time that a user would see on a watch or calendar.
|
478 | *
|
479 | * @param {object|string} value The time. If a string, this should be in the
|
480 | * format the API describes: `YYYY-[M]M-[D]D[ [H]H:[M]M:[S]S[.DDDDDD]]`.
|
481 | * Otherwise, provide an object.
|
482 | * @param {string|number} value.year Four digits.
|
483 | * @param {string|number} value.month One or two digits.
|
484 | * @param {string|number} value.day One or two digits.
|
485 | * @param {string|number} [value.hours] One or two digits (`00` - `23`).
|
486 | * @param {string|number} [value.minutes] One or two digits (`00` - `59`).
|
487 | * @param {string|number} [value.seconds] One or two digits (`00` - `59`).
|
488 | * @param {string|number} [value.fractional] Up to six digits for microsecond
|
489 | * precision.
|
490 | *
|
491 | * @example
|
492 | * ```
|
493 | * const {BigQuery} = require('@google-cloud/bigquery');
|
494 | * const bigquery = new BigQuery();
|
495 | * const datetime = bigquery.datetime('2017-01-01 13:00:00');
|
496 | *
|
497 | * //-
|
498 | * // Alternatively, provide an object.
|
499 | * //-
|
500 | * const datetime = bigquery.datetime({
|
501 | * year: 2017,
|
502 | * month: 1,
|
503 | * day: 1,
|
504 | * hours: 14,
|
505 | * minutes: 0,
|
506 | * seconds: 0
|
507 | * });
|
508 | * ```
|
509 | */
|
510 | static datetime(value) {
|
511 | return new BigQueryDatetime(value);
|
512 | }
|
513 | datetime(value) {
|
514 | return BigQuery.datetime(value);
|
515 | }
|
516 | /**
|
517 | * A `TIME` data type represents a time, independent of a specific date.
|
518 | *
|
519 | * @method BigQuery.time
|
520 | * @param {object|string} value The time. If a string, this should be in the
|
521 | * format the API describes: `[H]H:[M]M:[S]S[.DDDDDD]`. Otherwise, provide
|
522 | * an object.
|
523 | * @param {string|number} [value.hours] One or two digits (`00` - `23`).
|
524 | * @param {string|number} [value.minutes] One or two digits (`00` - `59`).
|
525 | * @param {string|number} [value.seconds] One or two digits (`00` - `59`).
|
526 | * @param {string|number} [value.fractional] Up to six digits for microsecond
|
527 | * precision.
|
528 | *
|
529 | * @example
|
530 | * ```
|
531 | * const {BigQuery} = require('@google-cloud/bigquery');
|
532 | * const time = BigQuery.time('14:00:00'); // 2:00 PM
|
533 | *
|
534 | * //-
|
535 | * // Alternatively, provide an object.
|
536 | * //-
|
537 | * const time = BigQuery.time({
|
538 | * hours: 14,
|
539 | * minutes: 0,
|
540 | * seconds: 0
|
541 | * });
|
542 | * ```
|
543 | */
|
544 | /**
|
545 | * A `TIME` data type represents a time, independent of a specific date.
|
546 | *
|
547 | * @param {object|string} value The time. If a string, this should be in the
|
548 | * format the API describes: `[H]H:[M]M:[S]S[.DDDDDD]`. Otherwise, provide
|
549 | * an object.
|
550 | * @param {string|number} [value.hours] One or two digits (`00` - `23`).
|
551 | * @param {string|number} [value.minutes] One or two digits (`00` - `59`).
|
552 | * @param {string|number} [value.seconds] One or two digits (`00` - `59`).
|
553 | * @param {string|number} [value.fractional] Up to six digits for microsecond
|
554 | * precision.
|
555 | *
|
556 | * @example
|
557 | * ```
|
558 | * const {BigQuery} = require('@google-cloud/bigquery');
|
559 | * const bigquery = new BigQuery();
|
560 | * const time = bigquery.time('14:00:00'); // 2:00 PM
|
561 | *
|
562 | * //-
|
563 | * // Alternatively, provide an object.
|
564 | * //-
|
565 | * const time = bigquery.time({
|
566 | * hours: 14,
|
567 | * minutes: 0,
|
568 | * seconds: 0
|
569 | * });
|
570 | * ```
|
571 | */
|
572 | static time(value) {
|
573 | return new BigQueryTime(value);
|
574 | }
|
575 | time(value) {
|
576 | return BigQuery.time(value);
|
577 | }
|
578 | /**
|
579 | * A timestamp represents an absolute point in time, independent of any time
|
580 | * zone or convention such as Daylight Savings Time.
|
581 | *
|
582 | * @method BigQuery.timestamp
|
583 | * @param {Date|string} value The time.
|
584 | *
|
585 | * @example
|
586 | * ```
|
587 | * const {BigQuery} = require('@google-cloud/bigquery');
|
588 | * const timestamp = BigQuery.timestamp(new Date());
|
589 | * ```
|
590 | */
|
591 | /**
|
592 | * A timestamp represents an absolute point in time, independent of any time
|
593 | * zone or convention such as Daylight Savings Time.
|
594 | *
|
595 | * @param {Date|string} value The time.
|
596 | *
|
597 | * @example
|
598 | * ```
|
599 | * const {BigQuery} = require('@google-cloud/bigquery');
|
600 | * const bigquery = new BigQuery();
|
601 | * const timestamp = bigquery.timestamp(new Date());
|
602 | * ```
|
603 | */
|
604 | static timestamp(value) {
|
605 | return new BigQueryTimestamp(value);
|
606 | }
|
607 | timestamp(value) {
|
608 | return BigQuery.timestamp(value);
|
609 | }
|
610 | /**
|
611 | * A BigQueryInt wraps 'INT64' values. Can be used to maintain precision.
|
612 | *
|
613 | * @param {string|number|IntegerTypeCastValue} value The INT64 value to convert.
|
614 | * @param {IntegerTypeCastOptions} typeCastOptions Configuration to convert
|
615 | * value. Must provide an `integerTypeCastFunction` to handle conversion.
|
616 | * @returns {BigQueryInt}
|
617 | *
|
618 | * @example
|
619 | * ```
|
620 | * const {BigQuery} = require('@google-cloud/bigquery');
|
621 | * const bigquery = new BigQuery();
|
622 | *
|
623 | * const largeIntegerValue = Number.MAX_SAFE_INTEGER + 1;
|
624 | *
|
625 | * const options = {
|
626 | * integerTypeCastFunction: value => value.split(),
|
627 | * };
|
628 | *
|
629 | * const bqInteger = bigquery.int(largeIntegerValue, options);
|
630 | *
|
631 | * const customValue = bqInteger.valueOf();
|
632 | * // customValue is the value returned from your `integerTypeCastFunction`.
|
633 | * ```
|
634 | */
|
635 | static int(value, typeCastOptions) {
|
636 | return new BigQueryInt(value, typeCastOptions);
|
637 | }
|
638 | int(value, typeCastOptions) {
|
639 | return BigQuery.int(value, typeCastOptions);
|
640 | }
|
641 | /**
|
642 | * A geography value represents a surface area on the Earth
|
643 | * in Well-known Text (WKT) format.
|
644 | *
|
645 | * @param {string} value The geospatial data.
|
646 | *
|
647 | * @example
|
648 | * ```
|
649 | * const {BigQuery} = require('@google-cloud/bigquery');
|
650 | * const bigquery = new BigQuery();
|
651 | * const geography = bigquery.geography('POINT(1, 2)');
|
652 | * ```
|
653 | */
|
654 | static geography(value) {
|
655 | return new Geography(value);
|
656 | }
|
657 | geography(value) {
|
658 | return BigQuery.geography(value);
|
659 | }
|
660 | /**
|
661 | * Convert an INT64 value to Number.
|
662 | *
|
663 | * @private
|
664 | * @param {object} value The INT64 value to convert.
|
665 | */
|
666 | static decodeIntegerValue_(value) {
|
667 | const num = Number(value.integerValue);
|
668 | if (!Number.isSafeInteger(num)) {
|
669 | throw new Error('We attempted to return all of the numeric values, but ' +
|
670 | (value.schemaFieldName ? value.schemaFieldName + ' ' : '') +
|
671 | 'value ' +
|
672 | value.integerValue +
|
673 | " is out of bounds of 'Number.MAX_SAFE_INTEGER'.\n" +
|
674 | "To prevent this error, please consider passing 'options.wrapNumbers' as\n" +
|
675 | '{\n' +
|
676 | ' integerTypeCastFunction: provide <your_custom_function>\n' +
|
677 | ' fields: optionally specify field name(s) to be custom casted\n' +
|
678 | '}\n');
|
679 | }
|
680 | return num;
|
681 | }
|
682 | /**
|
683 | * Return a value's provided type.
|
684 | *
|
685 | * @private
|
686 | *
|
687 | * @throws {error} If the type provided is invalid.
|
688 | *
|
689 | * See {@link https://cloud.google.com/bigquery/data-types| Data Type}
|
690 | *
|
691 | * @param {*} providedType The type.
|
692 | * @returns {string} The valid type provided.
|
693 | */
|
694 | static getTypeDescriptorFromProvidedType_(providedType) {
|
695 | // The list of types can be found in src/types.d.ts
|
696 | const VALID_TYPES = [
|
697 | 'DATE',
|
698 | 'DATETIME',
|
699 | 'TIME',
|
700 | 'TIMESTAMP',
|
701 | 'BYTES',
|
702 | 'NUMERIC',
|
703 | 'BIGNUMERIC',
|
704 | 'BOOL',
|
705 | 'INT64',
|
706 | 'FLOAT64',
|
707 | 'STRING',
|
708 | 'GEOGRAPHY',
|
709 | 'ARRAY',
|
710 | 'STRUCT',
|
711 | ];
|
712 | if (is.array(providedType)) {
|
713 | providedType = providedType;
|
714 | return {
|
715 | type: 'ARRAY',
|
716 | arrayType: BigQuery.getTypeDescriptorFromProvidedType_(providedType[0]),
|
717 | };
|
718 | }
|
719 | else if (is.object(providedType)) {
|
720 | return {
|
721 | type: 'STRUCT',
|
722 | structTypes: Object.keys(providedType).map(prop => {
|
723 | return {
|
724 | name: prop,
|
725 | type: BigQuery.getTypeDescriptorFromProvidedType_(providedType[prop]),
|
726 | };
|
727 | }),
|
728 | };
|
729 | }
|
730 | providedType = providedType.toUpperCase();
|
731 | if (!VALID_TYPES.includes(providedType)) {
|
732 | throw new Error(`Invalid type provided: "${providedType}"`);
|
733 | }
|
734 | return { type: providedType.toUpperCase() };
|
735 | }
|
736 | /**
|
737 | * Detect a value's type.
|
738 | *
|
739 | * @private
|
740 | *
|
741 | * @throws {error} If the type could not be detected.
|
742 | *
|
743 | * See {@link https://cloud.google.com/bigquery/data-types| Data Type}
|
744 | *
|
745 | * @param {*} value The value.
|
746 | * @returns {string} The type detected from the value.
|
747 | */
|
748 | static getTypeDescriptorFromValue_(value) {
|
749 | let typeName;
|
750 | if (value === null) {
|
751 | throw new Error("Parameter types must be provided for null values via the 'types' field in query options.");
|
752 | }
|
753 | if (value instanceof BigQueryDate) {
|
754 | typeName = 'DATE';
|
755 | }
|
756 | else if (value instanceof BigQueryDatetime) {
|
757 | typeName = 'DATETIME';
|
758 | }
|
759 | else if (value instanceof BigQueryTime) {
|
760 | typeName = 'TIME';
|
761 | }
|
762 | else if (value instanceof BigQueryTimestamp) {
|
763 | typeName = 'TIMESTAMP';
|
764 | }
|
765 | else if (value instanceof Buffer) {
|
766 | typeName = 'BYTES';
|
767 | }
|
768 | else if (value instanceof big_js_1.Big) {
|
769 | if (value.c.length - value.e >= 10) {
|
770 | typeName = 'BIGNUMERIC';
|
771 | }
|
772 | else {
|
773 | typeName = 'NUMERIC';
|
774 | }
|
775 | }
|
776 | else if (value instanceof BigQueryInt) {
|
777 | typeName = 'INT64';
|
778 | }
|
779 | else if (value instanceof Geography) {
|
780 | typeName = 'GEOGRAPHY';
|
781 | }
|
782 | else if (Array.isArray(value)) {
|
783 | if (value.length === 0) {
|
784 | throw new Error("Parameter types must be provided for empty arrays via the 'types' field in query options.");
|
785 | }
|
786 | return {
|
787 | type: 'ARRAY',
|
788 | arrayType: BigQuery.getTypeDescriptorFromValue_(value[0]),
|
789 | };
|
790 | }
|
791 | else if (is.boolean(value)) {
|
792 | typeName = 'BOOL';
|
793 | }
|
794 | else if (is.number(value)) {
|
795 | typeName = value % 1 === 0 ? 'INT64' : 'FLOAT64';
|
796 | }
|
797 | else if (is.object(value)) {
|
798 | return {
|
799 | type: 'STRUCT',
|
800 | structTypes: Object.keys(value).map(prop => {
|
801 | return {
|
802 | name: prop,
|
803 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
804 | type: BigQuery.getTypeDescriptorFromValue_(value[prop]),
|
805 | };
|
806 | }),
|
807 | };
|
808 | }
|
809 | else if (is.string(value)) {
|
810 | typeName = 'STRING';
|
811 | }
|
812 | if (!typeName) {
|
813 | throw new Error([
|
814 | 'This value could not be translated to a BigQuery data type.',
|
815 | value,
|
816 | ].join('\n'));
|
817 | }
|
818 | return {
|
819 | type: typeName,
|
820 | };
|
821 | }
|
822 | /**
|
823 | * Convert a value into a `queryParameter` object.
|
824 | *
|
825 | * @private
|
826 | *
|
827 | * See {@link https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#request-body| Jobs.query API Reference Docs (see `queryParameters`)}
|
828 | *
|
829 | * @param {*} value The value.
|
830 | * @param {string|ProvidedTypeStruct|ProvidedTypeArray} providedType Provided
|
831 | * query parameter type.
|
832 | * @returns {object} A properly-formed `queryParameter` object.
|
833 | */
|
834 | static valueToQueryParameter_(
|
835 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
836 | value, providedType) {
|
837 | if (is.date(value)) {
|
838 | value = BigQuery.timestamp(value);
|
839 | }
|
840 | let parameterType;
|
841 | if (providedType) {
|
842 | parameterType = BigQuery.getTypeDescriptorFromProvidedType_(providedType);
|
843 | }
|
844 | else {
|
845 | parameterType = BigQuery.getTypeDescriptorFromValue_(value);
|
846 | }
|
847 | const queryParameter = { parameterType, parameterValue: {} };
|
848 | const typeName = queryParameter.parameterType.type;
|
849 | if (typeName === 'ARRAY') {
|
850 | queryParameter.parameterValue.arrayValues = value.map(itemValue => {
|
851 | const value = BigQuery._getValue(itemValue, parameterType.arrayType);
|
852 | if (is.object(value) || is.array(value)) {
|
853 | if (is.array(providedType)) {
|
854 | providedType = providedType;
|
855 | return BigQuery.valueToQueryParameter_(value, providedType[0])
|
856 | .parameterValue;
|
857 | }
|
858 | else {
|
859 | return BigQuery.valueToQueryParameter_(value).parameterValue;
|
860 | }
|
861 | }
|
862 | return { value };
|
863 | });
|
864 | }
|
865 | else if (typeName === 'STRUCT') {
|
866 | queryParameter.parameterValue.structValues = Object.keys(value).reduce((structValues, prop) => {
|
867 | let nestedQueryParameter;
|
868 | if (providedType) {
|
869 | nestedQueryParameter = BigQuery.valueToQueryParameter_(value[prop], providedType[prop]);
|
870 | }
|
871 | else {
|
872 | nestedQueryParameter = BigQuery.valueToQueryParameter_(value[prop]);
|
873 | }
|
874 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
875 | structValues[prop] = nestedQueryParameter.parameterValue;
|
876 | return structValues;
|
877 | }, {});
|
878 | }
|
879 | else {
|
880 | queryParameter.parameterValue.value = BigQuery._getValue(value, parameterType);
|
881 | }
|
882 | return queryParameter;
|
883 | }
|
884 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
885 | static _getValue(value, type) {
|
886 | if (value === null) {
|
887 | return null;
|
888 | }
|
889 | if (value.type)
|
890 | type = value;
|
891 | return BigQuery._isCustomType(type) ? value.value : value;
|
892 | }
|
893 | static _isCustomType({ type }) {
|
894 | return (type.indexOf('TIME') > -1 ||
|
895 | type.indexOf('DATE') > -1 ||
|
896 | type.indexOf('GEOGRAPHY') > -1 ||
|
897 | type.indexOf('BigQueryInt') > -1);
|
898 | }
|
899 | createDataset(id, optionsOrCallback, cb) {
|
900 | const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
|
901 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
902 | this.request({
|
903 | method: 'POST',
|
904 | uri: '/datasets',
|
905 | json: extend(true, {
|
906 | location: this.location,
|
907 | }, options, {
|
908 | datasetReference: {
|
909 | datasetId: id,
|
910 | },
|
911 | }),
|
912 | }, (err, resp) => {
|
913 | if (err) {
|
914 | callback(err, null, resp);
|
915 | return;
|
916 | }
|
917 | const dataset = this.dataset(id);
|
918 | dataset.metadata = resp;
|
919 | callback(null, dataset, resp);
|
920 | });
|
921 | }
|
922 | createQueryJob(opts, callback) {
|
923 | const options = typeof opts === 'object' ? opts : { query: opts };
|
924 | if ((!options || !options.query) && !options.pageToken) {
|
925 | throw new Error('A SQL query string is required.');
|
926 | }
|
927 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
928 | const query = extend(true, {
|
929 | useLegacySql: false,
|
930 | }, options);
|
931 | if (options.destination) {
|
932 | if (!(options.destination instanceof table_1.Table)) {
|
933 | throw new Error('Destination must be a Table object.');
|
934 | }
|
935 | query.destinationTable = {
|
936 | datasetId: options.destination.dataset.id,
|
937 | projectId: options.destination.dataset.bigQuery.projectId,
|
938 | tableId: options.destination.id,
|
939 | };
|
940 | delete query.destination;
|
941 | }
|
942 | if (query.params) {
|
943 | query.parameterMode = is.array(query.params) ? 'positional' : 'named';
|
944 | if (query.parameterMode === 'named') {
|
945 | query.queryParameters = [];
|
946 | // tslint:disable-next-line forin
|
947 | for (const namedParameter in query.params) {
|
948 | const value = query.params[namedParameter];
|
949 | let queryParameter;
|
950 | if (query.types) {
|
951 | if (!is.object(query.types)) {
|
952 | throw new Error('Provided types must match the value type passed to `params`');
|
953 | }
|
954 | if (query.types[namedParameter]) {
|
955 | queryParameter = BigQuery.valueToQueryParameter_(value, query.types[namedParameter]);
|
956 | }
|
957 | else {
|
958 | queryParameter = BigQuery.valueToQueryParameter_(value);
|
959 | }
|
960 | }
|
961 | else {
|
962 | queryParameter = BigQuery.valueToQueryParameter_(value);
|
963 | }
|
964 | queryParameter.name = namedParameter;
|
965 | query.queryParameters.push(queryParameter);
|
966 | }
|
967 | }
|
968 | else {
|
969 | query.queryParameters = [];
|
970 | if (query.types) {
|
971 | if (!is.array(query.types)) {
|
972 | throw new Error('Provided types must match the value type passed to `params`');
|
973 | }
|
974 | if (query.params.length !== query.types.length) {
|
975 | throw new Error('Incorrect number of parameter types provided.');
|
976 | }
|
977 | query.params.forEach((value, i) => {
|
978 | const queryParameter = BigQuery.valueToQueryParameter_(value, query.types[i]);
|
979 | query.queryParameters.push(queryParameter);
|
980 | });
|
981 | }
|
982 | else {
|
983 | query.params.forEach((value) => {
|
984 | const queryParameter = BigQuery.valueToQueryParameter_(value);
|
985 | query.queryParameters.push(queryParameter);
|
986 | });
|
987 | }
|
988 | }
|
989 | delete query.params;
|
990 | }
|
991 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
992 | const reqOpts = {
|
993 | configuration: {
|
994 | query,
|
995 | },
|
996 | };
|
997 | if (typeof query.jobTimeoutMs === 'number') {
|
998 | reqOpts.configuration.jobTimeoutMs = query.jobTimeoutMs;
|
999 | delete query.jobTimeoutMs;
|
1000 | }
|
1001 | if (query.dryRun) {
|
1002 | reqOpts.configuration.dryRun = query.dryRun;
|
1003 | delete query.dryRun;
|
1004 | }
|
1005 | if (query.labels) {
|
1006 | reqOpts.configuration.labels = query.labels;
|
1007 | delete query.labels;
|
1008 | }
|
1009 | if (query.jobPrefix) {
|
1010 | reqOpts.jobPrefix = query.jobPrefix;
|
1011 | delete query.jobPrefix;
|
1012 | }
|
1013 | if (query.location) {
|
1014 | reqOpts.location = query.location;
|
1015 | delete query.location;
|
1016 | }
|
1017 | if (query.jobId) {
|
1018 | reqOpts.jobId = query.jobId;
|
1019 | delete query.jobId;
|
1020 | }
|
1021 | this.createJob(reqOpts, callback);
|
1022 | }
|
1023 | createJob(options, callback) {
|
1024 | var _a;
|
1025 | const JOB_ID_PROVIDED = typeof options.jobId !== 'undefined';
|
1026 | const DRY_RUN = ((_a = options.configuration) === null || _a === void 0 ? void 0 : _a.dryRun)
|
1027 | ? options.configuration.dryRun
|
1028 | : false;
|
1029 | const reqOpts = Object.assign({}, options);
|
1030 | let jobId = JOB_ID_PROVIDED ? reqOpts.jobId : uuid.v4();
|
1031 | if (reqOpts.jobId) {
|
1032 | delete reqOpts.jobId;
|
1033 | }
|
1034 | if (reqOpts.jobPrefix) {
|
1035 | jobId = reqOpts.jobPrefix + jobId;
|
1036 | delete reqOpts.jobPrefix;
|
1037 | }
|
1038 | reqOpts.jobReference = {
|
1039 | projectId: this.projectId,
|
1040 | jobId,
|
1041 | location: this.location,
|
1042 | };
|
1043 | if (options.location) {
|
1044 | reqOpts.jobReference.location = options.location;
|
1045 | delete reqOpts.location;
|
1046 | }
|
1047 | const job = this.job(jobId, {
|
1048 | location: reqOpts.jobReference.location,
|
1049 | });
|
1050 | this.request({
|
1051 | method: 'POST',
|
1052 | uri: '/jobs',
|
1053 | json: reqOpts,
|
1054 | }, async (err, resp) => {
|
1055 | const ALREADY_EXISTS_CODE = 409;
|
1056 | if (err) {
|
1057 | if (err.code === ALREADY_EXISTS_CODE &&
|
1058 | !JOB_ID_PROVIDED &&
|
1059 | !DRY_RUN) {
|
1060 | // The last insert attempt flaked, but the API still processed the
|
1061 | // request and created the job. Because of our "autoRetry" feature,
|
1062 | // we tried the request again, which tried to create it again,
|
1063 | // unnecessarily. We will get the job's metadata and treat it as if
|
1064 | // it just came back from the create call.
|
1065 | err = null;
|
1066 | [resp] = await job.getMetadata();
|
1067 | }
|
1068 | else {
|
1069 | callback(err, null, resp);
|
1070 | return;
|
1071 | }
|
1072 | }
|
1073 | if (resp.status.errors) {
|
1074 | err = new common_1.util.ApiError({
|
1075 | errors: resp.status.errors,
|
1076 | response: resp,
|
1077 | });
|
1078 | }
|
1079 | // Update the location with the one used by the API.
|
1080 | job.location = resp.jobReference.location;
|
1081 | job.metadata = resp;
|
1082 | callback(err, job, resp);
|
1083 | });
|
1084 | }
|
1085 | /**
|
1086 | * Create a reference to a dataset.
|
1087 | *
|
1088 | * @param {string} id ID of the dataset.
|
1089 | * @param {object} [options] Dataset options.
|
1090 | * @param {string} [options.location] The geographic location of the dataset.
|
1091 | * Required except for US and EU.
|
1092 | *
|
1093 | * @example
|
1094 | * ```
|
1095 | * const {BigQuery} = require('@google-cloud/bigquery');
|
1096 | * const bigquery = new BigQuery();
|
1097 | * const dataset = bigquery.dataset('higher_education');
|
1098 | * ```
|
1099 | */
|
1100 | dataset(id, options) {
|
1101 | if (typeof id !== 'string') {
|
1102 | throw new TypeError('A dataset ID is required.');
|
1103 | }
|
1104 | if (this.location) {
|
1105 | options = extend({ location: this.location }, options);
|
1106 | }
|
1107 | return new dataset_1.Dataset(this, id, options);
|
1108 | }
|
1109 | getDatasets(optionsOrCallback, cb) {
|
1110 | const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
|
1111 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
1112 | this.request({
|
1113 | uri: '/datasets',
|
1114 | qs: options,
|
1115 | }, (err, resp) => {
|
1116 | if (err) {
|
1117 | callback(err, null, null, resp);
|
1118 | return;
|
1119 | }
|
1120 | let nextQuery = null;
|
1121 | if (resp.nextPageToken) {
|
1122 | nextQuery = Object.assign({}, options, {
|
1123 | pageToken: resp.nextPageToken,
|
1124 | });
|
1125 | }
|
1126 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
1127 | const datasets = (resp.datasets || []).map((dataset) => {
|
1128 | const ds = this.dataset(dataset.datasetReference.datasetId, {
|
1129 | location: dataset.location,
|
1130 | });
|
1131 | ds.metadata = dataset;
|
1132 | return ds;
|
1133 | });
|
1134 | callback(null, datasets, nextQuery, resp);
|
1135 | });
|
1136 | }
|
1137 | getJobs(optionsOrCallback, cb) {
|
1138 | const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
|
1139 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
1140 | this.request({
|
1141 | uri: '/jobs',
|
1142 | qs: options,
|
1143 | useQuerystring: true,
|
1144 | }, (err, resp) => {
|
1145 | if (err) {
|
1146 | callback(err, null, null, resp);
|
1147 | return;
|
1148 | }
|
1149 | let nextQuery = null;
|
1150 | if (resp.nextPageToken) {
|
1151 | nextQuery = Object.assign({}, options, {
|
1152 | pageToken: resp.nextPageToken,
|
1153 | });
|
1154 | }
|
1155 | const jobs = (resp.jobs || []).map((jobObject) => {
|
1156 | const job = this.job(jobObject.jobReference.jobId, {
|
1157 | location: jobObject.jobReference.location,
|
1158 | });
|
1159 | job.metadata = jobObject;
|
1160 | return job;
|
1161 | });
|
1162 | callback(null, jobs, nextQuery, resp);
|
1163 | });
|
1164 | }
|
1165 | /**
|
1166 | * Create a reference to an existing job.
|
1167 | *
|
1168 | * @param {string} id ID of the job.
|
1169 | * @param {object} [options] Configuration object.
|
1170 | * @param {string} [options.location] The geographic location of the job.
|
1171 | * Required except for US and EU.
|
1172 | *
|
1173 | * @example
|
1174 | * ```
|
1175 | * const {BigQuery} = require('@google-cloud/bigquery');
|
1176 | * const bigquery = new BigQuery();
|
1177 | *
|
1178 | * const myExistingJob = bigquery.job('job-id');
|
1179 | * ```
|
1180 | */
|
1181 | job(id, options) {
|
1182 | if (this.location) {
|
1183 | options = extend({ location: this.location }, options);
|
1184 | }
|
1185 | return new job_1.Job(this, id, options);
|
1186 | }
|
1187 | query(query, optionsOrCallback, cb) {
|
1188 | let options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
|
1189 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
1190 | this.createQueryJob(query, (err, job, resp) => {
|
1191 | if (err) {
|
1192 | callback(err, null, resp);
|
1193 | return;
|
1194 | }
|
1195 | if (typeof query === 'object' && query.dryRun) {
|
1196 | callback(null, [], resp);
|
1197 | return;
|
1198 | }
|
1199 | // The Job is important for the `queryAsStream_` method, so a new query
|
1200 | // isn't created each time results are polled for.
|
1201 | options = extend({ job }, options);
|
1202 | job.getQueryResults(options, callback);
|
1203 | });
|
1204 | }
|
1205 | /**
|
1206 | * This method will be called by `createQueryStream()`. It is required to
|
1207 | * properly set the `autoPaginate` option value.
|
1208 | *
|
1209 | * @private
|
1210 | */
|
1211 | queryAsStream_(query, callback) {
|
1212 | if (query.job) {
|
1213 | query.job.getQueryResults(query, callback);
|
1214 | return;
|
1215 | }
|
1216 | const { location, maxResults, pageToken, wrapIntegers } = query;
|
1217 | const opts = {
|
1218 | location,
|
1219 | maxResults,
|
1220 | pageToken,
|
1221 | wrapIntegers,
|
1222 | autoPaginate: false,
|
1223 | };
|
1224 | delete query.location;
|
1225 | delete query.maxResults;
|
1226 | delete query.pageToken;
|
1227 | delete query.wrapIntegers;
|
1228 | this.query(query, opts, callback);
|
1229 | }
|
1230 | }
|
1231 | exports.BigQuery = BigQuery;
|
1232 | /*! Developer Documentation
|
1233 | *
|
1234 | * These methods can be auto-paginated.
|
1235 | */
|
1236 | paginator_1.paginator.extend(BigQuery, ['getDatasets', 'getJobs']);
|
1237 | /*! Developer Documentation
|
1238 | *
|
1239 | * All async methods (except for streams) will return a Promise in the event
|
1240 | * that a callback is omitted.
|
1241 | */
|
1242 | (0, promisify_1.promisifyAll)(BigQuery, {
|
1243 | exclude: [
|
1244 | 'dataset',
|
1245 | 'date',
|
1246 | 'datetime',
|
1247 | 'geography',
|
1248 | 'int',
|
1249 | 'job',
|
1250 | 'time',
|
1251 | 'timestamp',
|
1252 | ],
|
1253 | });
|
1254 | /**
|
1255 | * Date class for BigQuery.
|
1256 | */
|
1257 | class BigQueryDate {
|
1258 | constructor(value) {
|
1259 | if (typeof value === 'object') {
|
1260 | value = BigQuery.datetime(value).value;
|
1261 | }
|
1262 | this.value = value;
|
1263 | }
|
1264 | }
|
1265 | exports.BigQueryDate = BigQueryDate;
|
1266 | /**
|
1267 | * Geography class for BigQuery.
|
1268 | */
|
1269 | class Geography {
|
1270 | constructor(value) {
|
1271 | this.value = value;
|
1272 | }
|
1273 | }
|
1274 | exports.Geography = Geography;
|
1275 | /**
|
1276 | * Timestamp class for BigQuery.
|
1277 | */
|
1278 | class BigQueryTimestamp {
|
1279 | constructor(value) {
|
1280 | this.value = new Date(value).toJSON();
|
1281 | }
|
1282 | }
|
1283 | exports.BigQueryTimestamp = BigQueryTimestamp;
|
1284 | /**
|
1285 | * Datetime class for BigQuery.
|
1286 | */
|
1287 | class BigQueryDatetime {
|
1288 | constructor(value) {
|
1289 | if (typeof value === 'object') {
|
1290 | let time;
|
1291 | if (value.hours) {
|
1292 | time = BigQuery.time(value).value;
|
1293 | }
|
1294 | const y = value.year;
|
1295 | const m = value.month;
|
1296 | const d = value.day;
|
1297 | time = time ? ' ' + time : '';
|
1298 | value = `${y}-${m}-${d}${time}`;
|
1299 | }
|
1300 | else {
|
1301 | value = value.replace(/^(.*)T(.*)Z$/, '$1 $2');
|
1302 | }
|
1303 | this.value = value;
|
1304 | }
|
1305 | }
|
1306 | exports.BigQueryDatetime = BigQueryDatetime;
|
1307 | /**
|
1308 | * Time class for BigQuery.
|
1309 | */
|
1310 | class BigQueryTime {
|
1311 | constructor(value) {
|
1312 | if (typeof value === 'object') {
|
1313 | const h = value.hours;
|
1314 | const m = value.minutes || 0;
|
1315 | const s = value.seconds || 0;
|
1316 | const f = is.defined(value.fractional) ? '.' + value.fractional : '';
|
1317 | value = `${h}:${m}:${s}${f}`;
|
1318 | }
|
1319 | this.value = value;
|
1320 | }
|
1321 | }
|
1322 | exports.BigQueryTime = BigQueryTime;
|
1323 | /**
|
1324 | * Build a BigQueryInt object. For long integers, a string can be provided.
|
1325 | *
|
1326 | * @class
|
1327 | * @param {string|number|IntegerTypeCastValue} value The 'INT64' value.
|
1328 | * @param {object} [typeCastOptions] Configuration to convert
|
1329 | * values of 'INT64' type to a custom value. Must provide an
|
1330 | * `integerTypeCastFunction` to handle conversion.
|
1331 | * @param {function} typeCastOptions.integerTypeCastFunction A custom user
|
1332 | * provided function to convert value.
|
1333 | * @param {string|string[]} [typeCastOptions.fields] Schema field
|
1334 | * names to be converted using `integerTypeCastFunction`.
|
1335 | *
|
1336 | * @example
|
1337 | * ```
|
1338 | * const {BigQuery} = require('@google-cloud/bigquery');
|
1339 | * const bigquery = new BigQuery();
|
1340 | * const anInt = bigquery.int(7);
|
1341 | * ```
|
1342 | */
|
1343 | class BigQueryInt extends Number {
|
1344 | constructor(value, typeCastOptions) {
|
1345 | super(typeof value === 'object' ? value.integerValue : value);
|
1346 | this._schemaFieldName =
|
1347 | typeof value === 'object' ? value.schemaFieldName : undefined;
|
1348 | this.value =
|
1349 | typeof value === 'object'
|
1350 | ? value.integerValue.toString()
|
1351 | : value.toString();
|
1352 | this.type = 'BigQueryInt';
|
1353 | if (typeCastOptions) {
|
1354 | if (typeof typeCastOptions.integerTypeCastFunction !== 'function') {
|
1355 | throw new Error('integerTypeCastFunction is not a function or was not provided.');
|
1356 | }
|
1357 | const typeCastFields = typeCastOptions.fields
|
1358 | ? arrify(typeCastOptions.fields)
|
1359 | : undefined;
|
1360 | let customCast = true;
|
1361 | if (typeCastFields) {
|
1362 | customCast = this._schemaFieldName
|
1363 | ? typeCastFields.includes(this._schemaFieldName)
|
1364 | ? true
|
1365 | : false
|
1366 | : false;
|
1367 | }
|
1368 | customCast &&
|
1369 | (this.typeCastFunction = typeCastOptions.integerTypeCastFunction);
|
1370 | }
|
1371 | }
|
1372 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
1373 | valueOf() {
|
1374 | const shouldCustomCast = this.typeCastFunction ? true : false;
|
1375 | if (shouldCustomCast) {
|
1376 | try {
|
1377 | return this.typeCastFunction(this.value);
|
1378 | }
|
1379 | catch (error) {
|
1380 | error.message = `integerTypeCastFunction threw an error:\n\n - ${error.message}`;
|
1381 | throw error;
|
1382 | }
|
1383 | }
|
1384 | else {
|
1385 | // return this.value;
|
1386 | return BigQuery.decodeIntegerValue_({
|
1387 | integerValue: this.value,
|
1388 | schemaFieldName: this._schemaFieldName,
|
1389 | });
|
1390 | }
|
1391 | }
|
1392 | toJSON() {
|
1393 | return { type: this.type, value: this.value };
|
1394 | }
|
1395 | }
|
1396 | exports.BigQueryInt = BigQueryInt;
|
1397 | //# sourceMappingURL=bigquery.js.map |
\ | No newline at end of file |