@malloydata/db-bigquery 0.0.424 → 0.0.426

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -100,7 +100,7 @@ export declare class BigQueryConnection extends BaseConnection implements Connec
100
100
  private createBigQueryJobAndGetResults;
101
101
  private createBigQueryJob;
102
102
  initiateJobAndGetLinkToConsole(sqlCommand: string, dryRun?: boolean): Promise<string>;
103
- runSQLStream(sqlCommand: string, { rowLimit, abortSignal }?: RunSQLOptions): AsyncIterableIterator<QueryRecord>;
103
+ runSQLStream(sqlCommand: string, { rowLimit, abortSignal, queryMetadata }?: RunSQLOptions): AsyncIterableIterator<QueryRecord>;
104
104
  fetchTableMetadata(tablePath: string): Promise<TableMetadata>;
105
105
  close(): Promise<void>;
106
106
  }
@@ -43,6 +43,35 @@ const googleCommon = __importStar(require("@google-cloud/common"));
43
43
  const gaxios_1 = require("gaxios");
44
44
  const malloy_1 = require("@malloydata/malloy");
45
45
  const connection_1 = require("@malloydata/malloy/connection");
46
+ // BigQuery label grammar: keys and values are lowercase, <=63 chars, and
47
+ // [a-z0-9_-]; keys must start with a lowercase letter. Values are transformed
48
+ // to fit (lowercase, disallowed chars -> '_', truncate); a key that can't be
49
+ // made valid (e.g. it starts with a digit) is dropped. BigQuery's 64-label cap
50
+ // needs no check here: the contract allows fewer properties than that.
51
+ const BQ_MAX_LEN = 63;
52
+ function sanitizeBigQueryValue(value) {
53
+ return value
54
+ .toLowerCase()
55
+ .replace(/[^a-z0-9_-]/g, '_')
56
+ .slice(0, BQ_MAX_LEN);
57
+ }
58
+ function sanitizeBigQueryKey(key) {
59
+ const sanitized = sanitizeBigQueryValue(key);
60
+ return /^[a-z]/.test(sanitized) ? sanitized : undefined;
61
+ }
62
+ /** Render a query's metadata as BigQuery job labels, in BQ's grammar. */
63
+ function toBigQueryLabels(labels) {
64
+ if (labels === undefined)
65
+ return undefined;
66
+ const out = {};
67
+ for (const [key, value] of Object.entries(labels)) {
68
+ const sanitizedKey = sanitizeBigQueryKey(key);
69
+ if (sanitizedKey === undefined)
70
+ continue; // can't be a valid BQ key; drop
71
+ out[sanitizedKey] = sanitizeBigQueryValue(value);
72
+ }
73
+ return Object.keys(out).length > 0 ? out : undefined;
74
+ }
46
75
  // BigQuery SDK apparently throws various authentication errors from Gaxios (https://github.com/googleapis/gaxios) and from
47
76
  // @google-cloud/common (https://www.npmjs.com/package/@google-cloud/common)
48
77
  // catching and rewriting here a single kind of authentication error we can consistently catch further up the stack
@@ -153,16 +182,18 @@ class BigQueryConnection extends connection_1.BaseConnection {
153
182
  get supportsNesting() {
154
183
  return true;
155
184
  }
156
- async _runSQL(sqlCommand, { rowLimit, abortSignal } = {}, rowIndex = 0) {
185
+ async _runSQL(sqlCommand, options = {}, rowIndex = 0) {
157
186
  var _a, _b, _c;
187
+ const { rowLimit, abortSignal } = options;
158
188
  const defaultOptions = this.readQueryOptions();
159
189
  const pageSize = rowLimit !== null && rowLimit !== void 0 ? rowLimit : defaultOptions.rowLimit;
190
+ const perCallLabels = toBigQueryLabels(this.queryMetadataBag(options.queryMetadata));
160
191
  try {
161
192
  const queryResultsOptions = {
162
193
  maxResults: pageSize,
163
194
  startIndex: rowIndex.toString(),
164
195
  };
165
- const jobResult = await this.createBigQueryJobAndGetResults(sqlCommand, undefined, queryResultsOptions, abortSignal);
196
+ const jobResult = await this.createBigQueryJobAndGetResults(sqlCommand, perCallLabels ? { labels: perCallLabels } : undefined, queryResultsOptions, abortSignal);
166
197
  const totalRows = +(((_a = jobResult[2]) === null || _a === void 0 ? void 0 : _a.totalRows)
167
198
  ? jobResult[2].totalRows
168
199
  : '0');
@@ -581,7 +612,8 @@ class BigQueryConnection extends connection_1.BaseConnection {
581
612
  const url = `https://console.cloud.google.com/bigquery?project=${this.billingProjectId}&j=bq:${job.location}:${job.id}&page=queryresults`;
582
613
  return url;
583
614
  }
584
- runSQLStream(sqlCommand, { rowLimit, abortSignal } = {}) {
615
+ runSQLStream(sqlCommand, { rowLimit, abortSignal, queryMetadata } = {}) {
616
+ const labels = toBigQueryLabels(this.queryMetadataBag(queryMetadata));
585
617
  const streamBigQuery = (onError, onData, onEnd) => {
586
618
  let index = 0;
587
619
  function handleData(rowMetadata) {
@@ -592,8 +624,9 @@ class BigQueryConnection extends connection_1.BaseConnection {
592
624
  this.end();
593
625
  }
594
626
  }
627
+ const query = this.prependSetupSQL(sqlCommand);
595
628
  this.bigQuery
596
- .createQueryStream(this.prependSetupSQL(sqlCommand))
629
+ .createQueryStream(labels ? { query, labels } : query)
597
630
  .on('error', onError)
598
631
  .on('data', handleData)
599
632
  .on('end', onEnd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/db-bigquery",
3
- "version": "0.0.424",
3
+ "version": "0.0.426",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -26,7 +26,7 @@
26
26
  "@google-cloud/bigquery": "7.9.4",
27
27
  "@google-cloud/common": "5.0.2",
28
28
  "@google-cloud/paginator": "5.0.2",
29
- "@malloydata/malloy": "0.0.424",
29
+ "@malloydata/malloy": "0.0.426",
30
30
  "gaxios": "^4.2.0"
31
31
  }
32
32
  }