@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,
|
|
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(
|
|
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.
|
|
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.
|
|
29
|
+
"@malloydata/malloy": "0.0.426",
|
|
30
30
|
"gaxios": "^4.2.0"
|
|
31
31
|
}
|
|
32
32
|
}
|