@lightdash/warehouses 2.228.1 → 2.229.0
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.
- package/dist/.tsbuildinfo.build +1 -0
- package/package.json +4 -4
- package/dist/.tsbuildinfo +0 -1
- package/dist/ssh/sshTunnelFailure.test.d.ts +0 -2
- package/dist/ssh/sshTunnelFailure.test.d.ts.map +0 -1
- package/dist/ssh/sshTunnelFailure.test.js +0 -90
- package/dist/validateWarehouseColumnReferences.test.d.ts +0 -2
- package/dist/validateWarehouseColumnReferences.test.d.ts.map +0 -1
- package/dist/validateWarehouseColumnReferences.test.js +0 -168
- package/dist/warehouseClients/AthenaWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/AthenaWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/AthenaWarehouseClient.test.js +0 -261
- package/dist/warehouseClients/BigqueryWarehouseClient.mock.d.ts +0 -83
- package/dist/warehouseClients/BigqueryWarehouseClient.mock.d.ts.map +0 -1
- package/dist/warehouseClients/BigqueryWarehouseClient.mock.js +0 -130
- package/dist/warehouseClients/BigqueryWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/BigqueryWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/BigqueryWarehouseClient.test.js +0 -493
- package/dist/warehouseClients/ClickhouseWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/ClickhouseWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/ClickhouseWarehouseClient.test.js +0 -115
- package/dist/warehouseClients/DatabricksWarehouseClient.mock.d.ts +0 -17
- package/dist/warehouseClients/DatabricksWarehouseClient.mock.d.ts.map +0 -1
- package/dist/warehouseClients/DatabricksWarehouseClient.mock.js +0 -111
- package/dist/warehouseClients/DatabricksWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/DatabricksWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/DatabricksWarehouseClient.test.js +0 -592
- package/dist/warehouseClients/DatabricksWarehouseStartupRetry.test.d.ts +0 -2
- package/dist/warehouseClients/DatabricksWarehouseStartupRetry.test.d.ts.map +0 -1
- package/dist/warehouseClients/DatabricksWarehouseStartupRetry.test.js +0 -129
- package/dist/warehouseClients/DuckdbWarehouseClient.embedded.test.d.ts +0 -2
- package/dist/warehouseClients/DuckdbWarehouseClient.embedded.test.d.ts.map +0 -1
- package/dist/warehouseClients/DuckdbWarehouseClient.embedded.test.js +0 -92
- package/dist/warehouseClients/DuckdbWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/DuckdbWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/DuckdbWarehouseClient.test.js +0 -1749
- package/dist/warehouseClients/MotherduckErrorClassifier.test.d.ts +0 -2
- package/dist/warehouseClients/MotherduckErrorClassifier.test.d.ts.map +0 -1
- package/dist/warehouseClients/MotherduckErrorClassifier.test.js +0 -31
- package/dist/warehouseClients/MotherduckInstanceCache.catalog.test.d.ts +0 -2
- package/dist/warehouseClients/MotherduckInstanceCache.catalog.test.d.ts.map +0 -1
- package/dist/warehouseClients/MotherduckInstanceCache.catalog.test.js +0 -52
- package/dist/warehouseClients/MotherduckInstanceCache.integration.test.d.ts +0 -2
- package/dist/warehouseClients/MotherduckInstanceCache.integration.test.d.ts.map +0 -1
- package/dist/warehouseClients/MotherduckInstanceCache.integration.test.js +0 -172
- package/dist/warehouseClients/MotherduckInstanceCache.security.test.d.ts +0 -2
- package/dist/warehouseClients/MotherduckInstanceCache.security.test.d.ts.map +0 -1
- package/dist/warehouseClients/MotherduckInstanceCache.security.test.js +0 -192
- package/dist/warehouseClients/MotherduckInstanceCache.test.d.ts +0 -2
- package/dist/warehouseClients/MotherduckInstanceCache.test.d.ts.map +0 -1
- package/dist/warehouseClients/MotherduckInstanceCache.test.js +0 -302
- package/dist/warehouseClients/PostgresWarehouseClient.mock.d.ts +0 -8
- package/dist/warehouseClients/PostgresWarehouseClient.mock.d.ts.map +0 -1
- package/dist/warehouseClients/PostgresWarehouseClient.mock.js +0 -66
- package/dist/warehouseClients/PostgresWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/PostgresWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/PostgresWarehouseClient.test.js +0 -371
- package/dist/warehouseClients/RedshiftWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/RedshiftWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/RedshiftWarehouseClient.test.js +0 -126
- package/dist/warehouseClients/SnowflakeWarehouseClient.mock.d.ts +0 -41
- package/dist/warehouseClients/SnowflakeWarehouseClient.mock.d.ts.map +0 -1
- package/dist/warehouseClients/SnowflakeWarehouseClient.mock.js +0 -184
- package/dist/warehouseClients/SnowflakeWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/SnowflakeWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/SnowflakeWarehouseClient.test.js +0 -777
- package/dist/warehouseClients/TrinoWarehouseClient.mock.d.ts +0 -23
- package/dist/warehouseClients/TrinoWarehouseClient.mock.d.ts.map +0 -1
- package/dist/warehouseClients/TrinoWarehouseClient.mock.js +0 -102
- package/dist/warehouseClients/TrinoWarehouseClient.test.d.ts +0 -2
- package/dist/warehouseClients/TrinoWarehouseClient.test.d.ts.map +0 -1
- package/dist/warehouseClients/TrinoWarehouseClient.test.js +0 -230
- package/dist/warehouseClients/WarehouseClient.mock.d.ts +0 -13
- package/dist/warehouseClients/WarehouseClient.mock.d.ts.map +0 -1
- package/dist/warehouseClients/WarehouseClient.mock.js +0 -51
- package/dist/warehouseClients/numericKinds.test.d.ts +0 -2
- package/dist/warehouseClients/numericKinds.test.d.ts.map +0 -1
- package/dist/warehouseClients/numericKinds.test.js +0 -168
- package/dist/warehouseClients/pgProtocolGuard.integration.test.d.ts +0 -2
- package/dist/warehouseClients/pgProtocolGuard.integration.test.d.ts.map +0 -1
- package/dist/warehouseClients/pgProtocolGuard.integration.test.js +0 -93
- package/dist/warehouseClients/pgProtocolGuard.test.d.ts +0 -2
- package/dist/warehouseClients/pgProtocolGuard.test.d.ts.map +0 -1
- package/dist/warehouseClients/pgProtocolGuard.test.js +0 -48
- package/dist/warehouseClients/redshiftIamCredentials.test.d.ts +0 -2
- package/dist/warehouseClients/redshiftIamCredentials.test.d.ts.map +0 -1
- package/dist/warehouseClients/redshiftIamCredentials.test.js +0 -210
- package/dist/warehouseClients/timestampDomain.test.d.ts +0 -2
- package/dist/warehouseClients/timestampDomain.test.d.ts.map +0 -1
- package/dist/warehouseClients/timestampDomain.test.js +0 -101
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createJobResponse = exports.rows = exports.getTableResponse = exports.credentials = void 0;
|
|
4
|
-
const bigquery_1 = require("@google-cloud/bigquery");
|
|
5
|
-
const common_1 = require("@lightdash/common");
|
|
6
|
-
const stream_1 = require("stream");
|
|
7
|
-
const BigqueryWarehouseClient_1 = require("./BigqueryWarehouseClient");
|
|
8
|
-
exports.credentials = {
|
|
9
|
-
type: common_1.WarehouseTypes.BIGQUERY,
|
|
10
|
-
project: 'myDatabase',
|
|
11
|
-
dataset: '',
|
|
12
|
-
timeoutSeconds: 0,
|
|
13
|
-
priority: 'interactive',
|
|
14
|
-
keyfileContents: {},
|
|
15
|
-
retries: 0,
|
|
16
|
-
location: '',
|
|
17
|
-
maximumBytesBilled: 0,
|
|
18
|
-
};
|
|
19
|
-
const metadata = {
|
|
20
|
-
schema: {
|
|
21
|
-
fields: [
|
|
22
|
-
{
|
|
23
|
-
name: 'myStringColumn',
|
|
24
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.STRING,
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
name: 'myNumberColumn',
|
|
28
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.NUMERIC,
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
name: 'myBigNumberColumn',
|
|
32
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.BIGNUMERIC,
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: 'myDateColumn',
|
|
36
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.DATE,
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: 'myTimestampColumn',
|
|
40
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.TIMESTAMP,
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
name: 'myBooleanColumn',
|
|
44
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.BOOLEAN,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
name: 'myArrayColumn',
|
|
48
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.ARRAY,
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
name: 'myObjectColumn',
|
|
52
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.STRUCT,
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: 'myRepeatedColumn',
|
|
56
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.STRING,
|
|
57
|
-
mode: 'REPEATED',
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: 'myRecordColumn',
|
|
61
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.RECORD,
|
|
62
|
-
mode: 'NULLABLE',
|
|
63
|
-
fields: [
|
|
64
|
-
{ name: 'id', type: BigqueryWarehouseClient_1.BigqueryFieldType.INT64 },
|
|
65
|
-
{ name: 'createdAt', type: BigqueryWarehouseClient_1.BigqueryFieldType.TIMESTAMP },
|
|
66
|
-
{
|
|
67
|
-
name: 'tags',
|
|
68
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.RECORD,
|
|
69
|
-
mode: 'REPEATED',
|
|
70
|
-
fields: [
|
|
71
|
-
{ name: 'label', type: BigqueryWarehouseClient_1.BigqueryFieldType.STRING },
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
exports.getTableResponse = {
|
|
80
|
-
id: 'myTable',
|
|
81
|
-
bigQuery: { projectId: 'myDatabase' },
|
|
82
|
-
getMetadata: vi.fn(() => [metadata]),
|
|
83
|
-
};
|
|
84
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
85
|
-
const [bigqueryDecimalValues] = bigquery_1.BigQuery.mergeSchemaWithRows_({
|
|
86
|
-
fields: [
|
|
87
|
-
{
|
|
88
|
-
name: 'myNumberColumn',
|
|
89
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.NUMERIC,
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
name: 'myBigNumberColumn',
|
|
93
|
-
type: BigqueryWarehouseClient_1.BigqueryFieldType.BIGNUMERIC,
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
}, [
|
|
97
|
-
{
|
|
98
|
-
f: [{ v: '100.25' }, { v: '200.5' }],
|
|
99
|
-
},
|
|
100
|
-
], { wrapIntegers: false });
|
|
101
|
-
exports.rows = [
|
|
102
|
-
{
|
|
103
|
-
myStringColumn: 'string value',
|
|
104
|
-
...bigqueryDecimalValues,
|
|
105
|
-
myDateColumn: new bigquery_1.BigQueryDate('2021-03-10'),
|
|
106
|
-
myTimestampColumn: new bigquery_1.BigQueryTimestamp('1990-03-02T08:30:00.010Z'),
|
|
107
|
-
myBooleanColumn: false,
|
|
108
|
-
myArrayColumn: ['1', '2', '3'],
|
|
109
|
-
myObjectColumn: { test: '1', toFixed: () => '123' },
|
|
110
|
-
myRepeatedColumn: ['a', 'b'],
|
|
111
|
-
myRecordColumn: {
|
|
112
|
-
id: 7,
|
|
113
|
-
createdAt: new bigquery_1.BigQueryTimestamp('1990-03-02T08:30:00.010Z'),
|
|
114
|
-
tags: [{ label: 'x' }, { label: 'y' }],
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
|
-
];
|
|
118
|
-
const mockStreamRow = () => new stream_1.Readable({
|
|
119
|
-
objectMode: true,
|
|
120
|
-
read() {
|
|
121
|
-
exports.rows.forEach((row) => this.push(row));
|
|
122
|
-
this.push(null);
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
exports.createJobResponse = [
|
|
126
|
-
{
|
|
127
|
-
getQueryResults: vi.fn(() => [exports.rows, undefined, metadata]),
|
|
128
|
-
getQueryResultsStream: vi.fn(mockStreamRow),
|
|
129
|
-
},
|
|
130
|
-
];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BigqueryWarehouseClient.test.d.ts","sourceRoot":"","sources":["../../src/warehouseClients/BigqueryWarehouseClient.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const bigquery_1 = require("@google-cloud/bigquery");
|
|
4
|
-
const common_1 = require("@lightdash/common");
|
|
5
|
-
const BigqueryWarehouseClient_1 = require("./BigqueryWarehouseClient");
|
|
6
|
-
const BigqueryWarehouseClient_mock_1 = require("./BigqueryWarehouseClient.mock");
|
|
7
|
-
const WarehouseClient_mock_1 = require("./WarehouseClient.mock");
|
|
8
|
-
describe('BigqueryWarehouseClient', () => {
|
|
9
|
-
it('expect query rows with mapped values', async () => {
|
|
10
|
-
const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(BigqueryWarehouseClient_mock_1.credentials);
|
|
11
|
-
warehouse.client.createQueryJob = vi.fn(() => BigqueryWarehouseClient_mock_1.createJobResponse);
|
|
12
|
-
const results = await warehouse.runQuery('fake sql');
|
|
13
|
-
expect(results.fields).toEqual({
|
|
14
|
-
...WarehouseClient_mock_1.expectedFields,
|
|
15
|
-
// NUMERIC is (38, 9) unless declared; BIGNUMERIC reports no kind
|
|
16
|
-
myNumberColumn: {
|
|
17
|
-
type: 'number',
|
|
18
|
-
numericKind: { kind: 'decimal', scale: 9 },
|
|
19
|
-
},
|
|
20
|
-
myBigNumberColumn: { type: 'number' },
|
|
21
|
-
myRepeatedColumn: { type: 'string' },
|
|
22
|
-
myRecordColumn: { type: 'string' },
|
|
23
|
-
});
|
|
24
|
-
expect(results.rows[0]).toEqual({
|
|
25
|
-
...WarehouseClient_mock_1.expectedRow,
|
|
26
|
-
myNumberColumn: 100.25,
|
|
27
|
-
myBigNumberColumn: 200.5,
|
|
28
|
-
// BigQuery serialises nested values as JSON; other clients pass them through
|
|
29
|
-
myArrayColumn: '["1","2","3"]',
|
|
30
|
-
myObjectColumn: '{"test":"1"}',
|
|
31
|
-
myRepeatedColumn: '["a","b"]',
|
|
32
|
-
myRecordColumn: '{"id":7,"createdAt":"1990-03-02T08:30:00.010Z","tags":[{"label":"x"},{"label":"y"}]}',
|
|
33
|
-
});
|
|
34
|
-
expect(warehouse.client.createQueryJob).toHaveBeenCalledTimes(1);
|
|
35
|
-
});
|
|
36
|
-
it('expect createQueryJob to set the time_zone connection property when a timezone is passed', async () => {
|
|
37
|
-
const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(BigqueryWarehouseClient_mock_1.credentials);
|
|
38
|
-
warehouse.client.createQueryJob = vi.fn(() => BigqueryWarehouseClient_mock_1.createJobResponse);
|
|
39
|
-
await warehouse.runQuery('fake sql', undefined, 'Asia/Tokyo');
|
|
40
|
-
expect(warehouse.client.createQueryJob).toHaveBeenCalledWith(expect.objectContaining({
|
|
41
|
-
connectionProperties: [
|
|
42
|
-
{ key: 'time_zone', value: 'Asia/Tokyo' },
|
|
43
|
-
],
|
|
44
|
-
}));
|
|
45
|
-
});
|
|
46
|
-
it('expect createQueryJob to omit connection properties when no timezone is passed', async () => {
|
|
47
|
-
const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(BigqueryWarehouseClient_mock_1.credentials);
|
|
48
|
-
warehouse.client.createQueryJob = vi.fn(() => BigqueryWarehouseClient_mock_1.createJobResponse);
|
|
49
|
-
await warehouse.runQuery('fake sql');
|
|
50
|
-
expect(warehouse.client.createQueryJob).toHaveBeenCalledWith(expect.objectContaining({
|
|
51
|
-
connectionProperties: undefined,
|
|
52
|
-
}));
|
|
53
|
-
});
|
|
54
|
-
it('expect schema with bigquery types mapped to dimension types', async () => {
|
|
55
|
-
const getTableMock = vi
|
|
56
|
-
.fn()
|
|
57
|
-
.mockImplementationOnce(() => BigqueryWarehouseClient_mock_1.getTableResponse);
|
|
58
|
-
bigquery_1.Dataset.prototype.table = getTableMock;
|
|
59
|
-
const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(BigqueryWarehouseClient_mock_1.credentials);
|
|
60
|
-
const expectedCatalog = structuredClone(WarehouseClient_mock_1.expectedWarehouseSchemaWithAwareTimestamp);
|
|
61
|
-
Object.assign(expectedCatalog.myDatabase.mySchema.myTable, {
|
|
62
|
-
myBigNumberColumn: common_1.DimensionType.NUMBER,
|
|
63
|
-
myRepeatedColumn: common_1.DimensionType.STRING,
|
|
64
|
-
myRecordColumn: common_1.DimensionType.STRING,
|
|
65
|
-
'myRecordColumn.id': common_1.DimensionType.NUMBER,
|
|
66
|
-
'myRecordColumn.createdAt': common_1.DimensionType.TIMESTAMP,
|
|
67
|
-
'myRecordColumn.tags': common_1.DimensionType.STRING,
|
|
68
|
-
'myRecordColumn.tags.label': common_1.DimensionType.STRING,
|
|
69
|
-
});
|
|
70
|
-
(0, common_1.setCatalogTimestampDomain)(expectedCatalog, 'myDatabase', 'mySchema', 'myTable', 'myRecordColumn.createdAt', 'aware');
|
|
71
|
-
const nestedShapes = {
|
|
72
|
-
myObjectColumn: { repeated: false, record: true },
|
|
73
|
-
myRepeatedColumn: { repeated: true, record: false },
|
|
74
|
-
myRecordColumn: { repeated: false, record: true },
|
|
75
|
-
'myRecordColumn.tags': { repeated: true, record: true },
|
|
76
|
-
};
|
|
77
|
-
Object.entries(nestedShapes).forEach(([path, shape]) => (0, common_1.setCatalogNestedColumnShape)(expectedCatalog, 'myDatabase', 'mySchema', 'myTable', path, shape));
|
|
78
|
-
expect(await warehouse.getCatalog(WarehouseClient_mock_1.config)).toEqual(expectedCatalog);
|
|
79
|
-
expect(getTableMock).toHaveBeenCalledTimes(1);
|
|
80
|
-
expect(BigqueryWarehouseClient_mock_1.getTableResponse.getMetadata).toHaveBeenCalledTimes(1);
|
|
81
|
-
});
|
|
82
|
-
it('expect getFields to flatten nested columns with the same shapes as getCatalog', async () => {
|
|
83
|
-
bigquery_1.Dataset.prototype.table = vi
|
|
84
|
-
.fn()
|
|
85
|
-
.mockImplementationOnce(() => BigqueryWarehouseClient_mock_1.getTableResponse);
|
|
86
|
-
const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(BigqueryWarehouseClient_mock_1.credentials);
|
|
87
|
-
const fields = await warehouse.getFields('myTable', 'mySchema', 'myDatabase');
|
|
88
|
-
expect(fields.myDatabase.mySchema.myTable['myRecordColumn.id']).toBe(common_1.DimensionType.NUMBER);
|
|
89
|
-
expect((0, common_1.getCatalogNestedColumnShape)(fields, 'myDatabase', 'mySchema', 'myTable', 'myRecordColumn.tags')).toEqual({ repeated: true, record: true });
|
|
90
|
-
expect((0, common_1.getCatalogNestedColumnShape)(fields, 'myDatabase', 'mySchema', 'myTable', 'myStringColumn')).toBeUndefined();
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
describe('BigqueryWarehouseClient.getDatabases', () => {
|
|
94
|
-
const createDataset = (datasetId) => new bigquery_1.Dataset(new bigquery_1.BigQuery({ projectId: 'test-project' }), datasetId, {
|
|
95
|
-
location: 'EU',
|
|
96
|
-
});
|
|
97
|
-
const createClient = (datasets, query) => ({
|
|
98
|
-
getDatasets: vi
|
|
99
|
-
.fn()
|
|
100
|
-
.mockResolvedValue([datasets]),
|
|
101
|
-
query: vi.fn(query),
|
|
102
|
-
});
|
|
103
|
-
it('includes the stored size for each dataset', async () => {
|
|
104
|
-
const datasets = [createDataset('small'), createDataset('large')];
|
|
105
|
-
const queryMock = vi
|
|
106
|
-
.fn()
|
|
107
|
-
.mockResolvedValueOnce([[{ sizeBytes: 100 }]])
|
|
108
|
-
.mockResolvedValueOnce([[{ sizeBytes: 500 }]]);
|
|
109
|
-
const client = createClient(datasets, queryMock);
|
|
110
|
-
await expect(BigqueryWarehouseClient_1.BigqueryWarehouseClient.getDatabases('test-project', 'refresh-token', client)).resolves.toEqual([
|
|
111
|
-
{
|
|
112
|
-
projectId: 'test-project',
|
|
113
|
-
datasetId: 'small',
|
|
114
|
-
location: 'EU',
|
|
115
|
-
sizeBytes: 100,
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
projectId: 'test-project',
|
|
119
|
-
datasetId: 'large',
|
|
120
|
-
location: 'EU',
|
|
121
|
-
sizeBytes: 500,
|
|
122
|
-
},
|
|
123
|
-
]);
|
|
124
|
-
expect(queryMock).toHaveBeenNthCalledWith(1, 'SELECT SUM(size_bytes) AS sizeBytes FROM `test-project.small.__TABLES__`');
|
|
125
|
-
});
|
|
126
|
-
it('returns null when an individual dataset size query fails', async () => {
|
|
127
|
-
const datasets = [createDataset('unavailable'), createDataset('ok')];
|
|
128
|
-
const queryMock = vi
|
|
129
|
-
.fn()
|
|
130
|
-
.mockRejectedValueOnce(new Error('permission denied'))
|
|
131
|
-
.mockResolvedValueOnce([[{ sizeBytes: 500 }]]);
|
|
132
|
-
const client = createClient(datasets, queryMock);
|
|
133
|
-
const result = await BigqueryWarehouseClient_1.BigqueryWarehouseClient.getDatabases('test-project', 'refresh-token', client);
|
|
134
|
-
expect(result.map(({ datasetId, sizeBytes }) => ({
|
|
135
|
-
datasetId,
|
|
136
|
-
sizeBytes,
|
|
137
|
-
}))).toEqual([
|
|
138
|
-
{ datasetId: 'unavailable', sizeBytes: null },
|
|
139
|
-
{ datasetId: 'ok', sizeBytes: 500 },
|
|
140
|
-
]);
|
|
141
|
-
});
|
|
142
|
-
it('only queries sizes for the first 25 datasets', async () => {
|
|
143
|
-
const datasets = Array.from({ length: 30 }, (_, index) => createDataset(`dataset_${index}`));
|
|
144
|
-
const queryMock = vi
|
|
145
|
-
.fn()
|
|
146
|
-
.mockResolvedValue([[{ sizeBytes: 100 }]]);
|
|
147
|
-
const client = createClient(datasets, queryMock);
|
|
148
|
-
const result = await BigqueryWarehouseClient_1.BigqueryWarehouseClient.getDatabases('test-project', 'refresh-token', client);
|
|
149
|
-
expect(queryMock).toHaveBeenCalledTimes(25);
|
|
150
|
-
expect(result.slice(0, 25).every(({ sizeBytes }) => sizeBytes === 100)).toBe(true);
|
|
151
|
-
expect(result.slice(25).every(({ sizeBytes }) => sizeBytes === null)).toBe(true);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
describe('BigqueryWarehouseClient.getProjectRecommendation', () => {
|
|
155
|
-
const createDataset = (projectId, datasetId, location) => new bigquery_1.Dataset(new bigquery_1.BigQuery({ projectId }), datasetId, {
|
|
156
|
-
location,
|
|
157
|
-
});
|
|
158
|
-
const createClient = (projectId, locations, queryImplementation) => {
|
|
159
|
-
const datasets = locations.map((location, index) => createDataset(projectId, `dataset_${index}`, location));
|
|
160
|
-
const getDatasets = vi.fn();
|
|
161
|
-
vi.mocked(getDatasets).mockResolvedValue([datasets]);
|
|
162
|
-
const query = vi.fn();
|
|
163
|
-
vi.mocked(query).mockImplementation(queryImplementation);
|
|
164
|
-
return { getDatasets, query };
|
|
165
|
-
};
|
|
166
|
-
it('ranks projects by their largest dataset across distinct regions', async () => {
|
|
167
|
-
const firstClient = createClient('first-project', ['EU', 'US', 'EU'], async ({ location }) => location === 'US'
|
|
168
|
-
? [[{ table_schema: 'largest', total_bytes: 1200 }]]
|
|
169
|
-
: [[{ table_schema: 'smaller', total_bytes: 500 }]]);
|
|
170
|
-
const secondClient = createClient('second-project', ['EU'], async () => [
|
|
171
|
-
[
|
|
172
|
-
{ table_schema: 'small', total_bytes: 100 },
|
|
173
|
-
{ table_schema: 'large', total_bytes: 900 },
|
|
174
|
-
],
|
|
175
|
-
]);
|
|
176
|
-
const clients = new Map([
|
|
177
|
-
['first-project', firstClient],
|
|
178
|
-
['second-project', secondClient],
|
|
179
|
-
]);
|
|
180
|
-
const clientFactory = vi.fn((projectId) => {
|
|
181
|
-
const client = clients.get(projectId);
|
|
182
|
-
if (!client)
|
|
183
|
-
throw new Error('Unexpected project');
|
|
184
|
-
return client;
|
|
185
|
-
});
|
|
186
|
-
const projects = [
|
|
187
|
-
{ projectId: 'first-project', friendlyName: null },
|
|
188
|
-
{ projectId: 'second-project', friendlyName: null },
|
|
189
|
-
];
|
|
190
|
-
await expect(BigqueryWarehouseClient_1.BigqueryWarehouseClient.getProjectRecommendation(projects, 'refresh-token', clientFactory)).resolves.toEqual({ projectId: 'first-project' });
|
|
191
|
-
expect(vi.mocked(firstClient.getDatasets)).toHaveBeenCalledWith({
|
|
192
|
-
autoPaginate: false,
|
|
193
|
-
maxResults: 1000,
|
|
194
|
-
});
|
|
195
|
-
expect(vi.mocked(firstClient.query)).toHaveBeenCalledTimes(2);
|
|
196
|
-
expect(vi.mocked(firstClient.query)).toHaveBeenCalledWith({
|
|
197
|
-
query: 'SELECT table_schema, SUM(total_logical_bytes) AS total_bytes FROM `first-project`.`region-us`.INFORMATION_SCHEMA.TABLE_STORAGE GROUP BY table_schema',
|
|
198
|
-
location: 'US',
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
it('skips a project when any of its region queries errors', async () => {
|
|
202
|
-
const failingClient = createClient('failing-project', ['EU', 'US'], async ({ location }) => {
|
|
203
|
-
if (location === 'US')
|
|
204
|
-
throw new Error('permission denied');
|
|
205
|
-
return [[{ table_schema: 'largest', total_bytes: 5000 }]];
|
|
206
|
-
});
|
|
207
|
-
const healthyClient = createClient('healthy-project', ['EU'], async () => [[{ table_schema: 'available', total_bytes: 100 }]]);
|
|
208
|
-
const clients = new Map([
|
|
209
|
-
['failing-project', failingClient],
|
|
210
|
-
['healthy-project', healthyClient],
|
|
211
|
-
]);
|
|
212
|
-
const clientFactory = vi.fn((projectId) => {
|
|
213
|
-
const client = clients.get(projectId);
|
|
214
|
-
if (!client)
|
|
215
|
-
throw new Error('Unexpected project');
|
|
216
|
-
return client;
|
|
217
|
-
});
|
|
218
|
-
await expect(BigqueryWarehouseClient_1.BigqueryWarehouseClient.getProjectRecommendation([
|
|
219
|
-
{ projectId: 'failing-project', friendlyName: null },
|
|
220
|
-
{ projectId: 'healthy-project', friendlyName: null },
|
|
221
|
-
], 'refresh-token', clientFactory)).resolves.toEqual({ projectId: 'healthy-project' });
|
|
222
|
-
});
|
|
223
|
-
it('returns no recommendation when every project score is unavailable', async () => {
|
|
224
|
-
const client = createClient('unavailable-project', ['EU'], async () => {
|
|
225
|
-
throw new Error('permission denied');
|
|
226
|
-
});
|
|
227
|
-
const clientFactory = vi.fn();
|
|
228
|
-
vi.mocked(clientFactory).mockReturnValue(client);
|
|
229
|
-
await expect(BigqueryWarehouseClient_1.BigqueryWarehouseClient.getProjectRecommendation([{ projectId: 'unavailable-project', friendlyName: null }], 'refresh-token', clientFactory)).resolves.toEqual({ projectId: null });
|
|
230
|
-
});
|
|
231
|
-
it('caps ranking at eight projects and three regions per project', async () => {
|
|
232
|
-
const projects = Array.from({ length: 10 }, (_, index) => ({
|
|
233
|
-
projectId: `project-${index}`,
|
|
234
|
-
friendlyName: null,
|
|
235
|
-
}));
|
|
236
|
-
const clients = new Map(projects.map(({ projectId }, index) => [
|
|
237
|
-
projectId,
|
|
238
|
-
createClient(projectId, ['EU', 'US', 'asia-east1', 'us-west1'], async () => [
|
|
239
|
-
[{ table_schema: 'dataset', total_bytes: index }],
|
|
240
|
-
]),
|
|
241
|
-
]));
|
|
242
|
-
const clientFactory = vi.fn((projectId) => {
|
|
243
|
-
const client = clients.get(projectId);
|
|
244
|
-
if (!client)
|
|
245
|
-
throw new Error('Unexpected project');
|
|
246
|
-
return client;
|
|
247
|
-
});
|
|
248
|
-
await expect(BigqueryWarehouseClient_1.BigqueryWarehouseClient.getProjectRecommendation(projects, 'refresh-token', clientFactory)).resolves.toEqual({ projectId: 'project-7' });
|
|
249
|
-
expect(vi.mocked(clientFactory)).toHaveBeenCalledTimes(8);
|
|
250
|
-
projects.forEach(({ projectId }, index) => {
|
|
251
|
-
const client = clients.get(projectId);
|
|
252
|
-
if (!client)
|
|
253
|
-
throw new Error('Unexpected project');
|
|
254
|
-
expect(vi.mocked(client.getDatasets)).toHaveBeenCalledTimes(index < 8 ? 1 : 0);
|
|
255
|
-
expect(vi.mocked(client.query)).toHaveBeenCalledTimes(index < 8 ? 3 : 0);
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
describe('BigqueryWarehouseClient.sanitizeLabelsWithValues', () => {
|
|
260
|
-
let warnSpy;
|
|
261
|
-
beforeEach(() => {
|
|
262
|
-
warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
263
|
-
});
|
|
264
|
-
afterEach(() => {
|
|
265
|
-
warnSpy.mockRestore();
|
|
266
|
-
});
|
|
267
|
-
it('returns undefined when given no labels', () => {
|
|
268
|
-
expect(BigqueryWarehouseClient_1.BigqueryWarehouseClient.sanitizeLabelsWithValues(undefined)).toBeUndefined();
|
|
269
|
-
});
|
|
270
|
-
it('lowercases and normalises string values', () => {
|
|
271
|
-
expect(BigqueryWarehouseClient_1.BigqueryWarehouseClient.sanitizeLabelsWithValues({
|
|
272
|
-
Scheduler_Uuid: 'ABC-123',
|
|
273
|
-
})).toEqual({ scheduler_uuid: 'abc-123' });
|
|
274
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
275
|
-
});
|
|
276
|
-
it('coerces numeric values without crashing and logs a warning', () => {
|
|
277
|
-
const result = BigqueryWarehouseClient_1.BigqueryWarehouseClient.sanitizeLabelsWithValues({
|
|
278
|
-
job_id: 224187,
|
|
279
|
-
});
|
|
280
|
-
expect(result).toEqual({ job_id: '224187' });
|
|
281
|
-
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('coerced non-string tag value'), { key: 'job_id', valueType: 'number' });
|
|
282
|
-
});
|
|
283
|
-
it('replaces null/undefined with empty_value silently', () => {
|
|
284
|
-
const result = BigqueryWarehouseClient_1.BigqueryWarehouseClient.sanitizeLabelsWithValues({
|
|
285
|
-
scheduler_name: null,
|
|
286
|
-
saved_sql_uuid: undefined,
|
|
287
|
-
});
|
|
288
|
-
expect(result).toEqual({
|
|
289
|
-
scheduler_name: 'empty_value',
|
|
290
|
-
saved_sql_uuid: 'empty_value',
|
|
291
|
-
});
|
|
292
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
293
|
-
});
|
|
294
|
-
it('coerces boolean values', () => {
|
|
295
|
-
const result = BigqueryWarehouseClient_1.BigqueryWarehouseClient.sanitizeLabelsWithValues({
|
|
296
|
-
embed: true,
|
|
297
|
-
});
|
|
298
|
-
expect(result).toEqual({ embed: 'true' });
|
|
299
|
-
expect(warnSpy).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ valueType: 'boolean' }));
|
|
300
|
-
});
|
|
301
|
-
it('sanitizes user attribute query tags for BigQuery labels', () => {
|
|
302
|
-
const result = BigqueryWarehouseClient_1.BigqueryWarehouseClient.sanitizeLabelsWithValues({
|
|
303
|
-
'user_attribute_User Tier': 'Enterprise Customer/EMEA',
|
|
304
|
-
user_attribute_company: "O'Reilly Media",
|
|
305
|
-
});
|
|
306
|
-
expect(result).toEqual({
|
|
307
|
-
user_attribute_user_tier: 'enterprise_customer_emea',
|
|
308
|
-
user_attribute_company: 'o_reilly_media',
|
|
309
|
-
});
|
|
310
|
-
expect(warnSpy).not.toHaveBeenCalled();
|
|
311
|
-
});
|
|
312
|
-
it('limits labels to the BigQuery maximum', () => {
|
|
313
|
-
const labels = Object.fromEntries(Array.from({ length: 70 }, (_, index) => [
|
|
314
|
-
`user_attribute_${index}`,
|
|
315
|
-
`value_${index}`,
|
|
316
|
-
]));
|
|
317
|
-
const result = BigqueryWarehouseClient_1.BigqueryWarehouseClient.sanitizeLabelsWithValues(labels);
|
|
318
|
-
expect(Object.keys(result ?? {})).toHaveLength(64);
|
|
319
|
-
});
|
|
320
|
-
it('keeps non-user-attribute labels when user attributes exceed the BigQuery maximum', () => {
|
|
321
|
-
const labels = {
|
|
322
|
-
...Object.fromEntries(Array.from({ length: 70 }, (_, index) => [
|
|
323
|
-
`user_attribute_${index}`,
|
|
324
|
-
`value_${index}`,
|
|
325
|
-
])),
|
|
326
|
-
query_uuid: 'query-uuid',
|
|
327
|
-
};
|
|
328
|
-
const result = BigqueryWarehouseClient_1.BigqueryWarehouseClient.sanitizeLabelsWithValues(labels);
|
|
329
|
-
expect(result).toEqual(expect.objectContaining({ query_uuid: 'query-uuid' }));
|
|
330
|
-
expect(Object.keys(result ?? {})).toHaveLength(64);
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
describe('BigquerySqlBuilder escaping', () => {
|
|
334
|
-
const bigquerySqlBuilder = new BigqueryWarehouseClient_1.BigquerySqlBuilder();
|
|
335
|
-
test('Should escape backslashes and quotes in bigquery', () => {
|
|
336
|
-
expect(bigquerySqlBuilder.escapeString("\\') OR (1=1) --")).toBe("\\\\\\') OR (1=1) ");
|
|
337
|
-
});
|
|
338
|
-
test('Should handle SQL injection attempts', () => {
|
|
339
|
-
// Test with a typical SQL injection pattern
|
|
340
|
-
const maliciousInput = "'; DROP TABLE users; --";
|
|
341
|
-
const escaped = bigquerySqlBuilder.escapeString(maliciousInput);
|
|
342
|
-
expect(escaped).toBe("\\'; DROP TABLE users; ");
|
|
343
|
-
// Test with another common SQL injection pattern
|
|
344
|
-
const anotherMaliciousInput = "' OR '1'='1";
|
|
345
|
-
const anotherEscaped = bigquerySqlBuilder.escapeString(anotherMaliciousInput);
|
|
346
|
-
expect(anotherEscaped).toBe("\\' OR \\'1\\'=\\'1");
|
|
347
|
-
});
|
|
348
|
-
test('Should NOT remove # comments from strings', () => {
|
|
349
|
-
// Test that # symbols are preserved in strings (not treated as comments)
|
|
350
|
-
const stringWithHash = 'Column name with # symbol';
|
|
351
|
-
const escaped = bigquerySqlBuilder.escapeString(stringWithHash);
|
|
352
|
-
expect(escaped).toBe('Column name with # symbol');
|
|
353
|
-
// Test that # at start of line is preserved
|
|
354
|
-
const hashAtStart = '#important-tag';
|
|
355
|
-
const escapedHashStart = bigquerySqlBuilder.escapeString(hashAtStart);
|
|
356
|
-
expect(escapedHashStart).toBe('#important-tag');
|
|
357
|
-
// Test multiple # symbols are preserved
|
|
358
|
-
const multipleHashes = 'value1#value2#value3';
|
|
359
|
-
const escapedMultiple = bigquerySqlBuilder.escapeString(multipleHashes);
|
|
360
|
-
expect(escapedMultiple).toBe('value1#value2#value3');
|
|
361
|
-
});
|
|
362
|
-
test('Should still remove -- and /* */ comments', () => {
|
|
363
|
-
// Test that -- comments are still removed
|
|
364
|
-
const stringWithDashComment = 'test value -- this is a comment';
|
|
365
|
-
const escapedDash = bigquerySqlBuilder.escapeString(stringWithDashComment);
|
|
366
|
-
expect(escapedDash).toBe('test value ');
|
|
367
|
-
// Test that /* */ comments are still removed
|
|
368
|
-
const stringWithBlockComment = 'test /* block comment */ value';
|
|
369
|
-
const escapedBlock = bigquerySqlBuilder.escapeString(stringWithBlockComment);
|
|
370
|
-
expect(escapedBlock).toBe('test value');
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
describe('BigquerySqlBuilder temporal literals', () => {
|
|
374
|
-
// BigQuery refuses to COALESCE mixed DATE/DATETIME/TIMESTAMP, so each
|
|
375
|
-
// temporal kind needs its own literal.
|
|
376
|
-
const builder = new BigqueryWarehouseClient_1.BigquerySqlBuilder();
|
|
377
|
-
const epoch = new Date(0);
|
|
378
|
-
test('casts to an aware TIMESTAMP', () => {
|
|
379
|
-
expect(builder.castToTimestamp(epoch)).toBe("TIMESTAMP('1970-01-01T00:00:00.000Z')");
|
|
380
|
-
});
|
|
381
|
-
test('casts to a DATE literal', () => {
|
|
382
|
-
expect(builder.castToDate(epoch)).toBe("DATE '1970-01-01'");
|
|
383
|
-
});
|
|
384
|
-
test('casts to a zoneless DATETIME literal', () => {
|
|
385
|
-
expect(builder.castToNaiveTimestamp(epoch)).toBe("DATETIME '1970-01-01 00:00:00'");
|
|
386
|
-
});
|
|
387
|
-
});
|
|
388
|
-
describe('BigqueryWarehouseClient Google OAuth token errors', () => {
|
|
389
|
-
const createGaxiosError = (data, message = data.error, status = 400) => Object.assign(new Error(message), {
|
|
390
|
-
status,
|
|
391
|
-
response: { status, data },
|
|
392
|
-
});
|
|
393
|
-
const invalidGrant = {
|
|
394
|
-
error: 'invalid_grant',
|
|
395
|
-
error_description: 'Token has been expired or revoked.',
|
|
396
|
-
error_subtype: 'invalid_rapt',
|
|
397
|
-
};
|
|
398
|
-
const userCredentials = {
|
|
399
|
-
...BigqueryWarehouseClient_mock_1.credentials,
|
|
400
|
-
authenticationType: common_1.BigqueryAuthenticationType.SSO,
|
|
401
|
-
keyfileContents: {
|
|
402
|
-
type: 'authorized_user',
|
|
403
|
-
client_id: 'client-id',
|
|
404
|
-
client_secret: 'client-secret',
|
|
405
|
-
refresh_token: 'refresh-token',
|
|
406
|
-
},
|
|
407
|
-
};
|
|
408
|
-
const serviceAccountCredentials = {
|
|
409
|
-
...BigqueryWarehouseClient_mock_1.credentials,
|
|
410
|
-
authenticationType: common_1.BigqueryAuthenticationType.PRIVATE_KEY,
|
|
411
|
-
keyfileContents: {
|
|
412
|
-
type: 'service_account',
|
|
413
|
-
client_email: 'robot@example.iam.gserviceaccount.com',
|
|
414
|
-
private_key: 'private-key',
|
|
415
|
-
},
|
|
416
|
-
};
|
|
417
|
-
const createWarehouseRejectingQueries = (warehouseCredentials, error) => {
|
|
418
|
-
const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(warehouseCredentials);
|
|
419
|
-
const createQueryJob = vi.fn();
|
|
420
|
-
vi.mocked(createQueryJob).mockRejectedValue(error);
|
|
421
|
-
warehouse.client.createQueryJob =
|
|
422
|
-
createQueryJob;
|
|
423
|
-
return warehouse;
|
|
424
|
-
};
|
|
425
|
-
const executeAsyncQuery = (warehouse) => warehouse.executeAsyncQuery({
|
|
426
|
-
sql: 'SELECT 1',
|
|
427
|
-
tags: {},
|
|
428
|
-
});
|
|
429
|
-
it('translates an invalid_grant rejection of a user keyfile into a BigqueryTokenError', async () => {
|
|
430
|
-
const warehouse = createWarehouseRejectingQueries(userCredentials, createGaxiosError(invalidGrant));
|
|
431
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toThrow(common_1.BigqueryTokenError);
|
|
432
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toThrow('Google rejected the BigQuery refresh token (invalid_grant: Token has been expired or revoked.; invalid_rapt). Reconnect your BigQuery account in personal settings.');
|
|
433
|
-
});
|
|
434
|
-
it('translates an invalid_grant rejection of a service account keyfile into a connection error', async () => {
|
|
435
|
-
const warehouse = createWarehouseRejectingQueries(serviceAccountCredentials, createGaxiosError(invalidGrant));
|
|
436
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toThrow(common_1.WarehouseConnectionError);
|
|
437
|
-
await expect(executeAsyncQuery(warehouse)).rejects.not.toThrow(common_1.BigqueryTokenError);
|
|
438
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toThrow('Google rejected the BigQuery credentials (invalid_grant: Token has been expired or revoked.; invalid_rapt).');
|
|
439
|
-
});
|
|
440
|
-
it('omits the subtype clause and falls back to invalid_grant alone', async () => {
|
|
441
|
-
const warehouse = createWarehouseRejectingQueries(userCredentials, createGaxiosError({ error: 'invalid_grant' }));
|
|
442
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toThrow('Google rejected the BigQuery refresh token (invalid_grant). Reconnect your BigQuery account in personal settings.');
|
|
443
|
-
});
|
|
444
|
-
it('leaves other 400 responses untranslated', async () => {
|
|
445
|
-
const original = createGaxiosError({
|
|
446
|
-
error: 'invalid_request',
|
|
447
|
-
error_description: 'Missing required parameter: refresh_token',
|
|
448
|
-
});
|
|
449
|
-
const warehouse = createWarehouseRejectingQueries(userCredentials, original);
|
|
450
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toBe(original);
|
|
451
|
-
});
|
|
452
|
-
it('detects invalid_grant from the response body, not the error message', async () => {
|
|
453
|
-
const warehouse = createWarehouseRejectingQueries(userCredentials, createGaxiosError(invalidGrant, 'Token has been expired or revoked.'));
|
|
454
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toThrow(common_1.BigqueryTokenError);
|
|
455
|
-
});
|
|
456
|
-
it('leaves a bare invalid_grant error without a response untranslated', async () => {
|
|
457
|
-
const original = new Error('invalid_grant');
|
|
458
|
-
const warehouse = createWarehouseRejectingQueries(userCredentials, original);
|
|
459
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toBe(original);
|
|
460
|
-
});
|
|
461
|
-
it('still translates structured BigQuery errors', async () => {
|
|
462
|
-
const warehouse = createWarehouseRejectingQueries(userCredentials, {
|
|
463
|
-
errors: [
|
|
464
|
-
{
|
|
465
|
-
reason: 'quotaExceeded',
|
|
466
|
-
message: 'Query exceeded the daily quota',
|
|
467
|
-
},
|
|
468
|
-
],
|
|
469
|
-
});
|
|
470
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toThrow(common_1.WarehouseQueryError);
|
|
471
|
-
await expect(executeAsyncQuery(warehouse)).rejects.toThrow('BigQuery quota exceeded. Query exceeded the daily quota');
|
|
472
|
-
});
|
|
473
|
-
it('translates an invalid_grant rejection raised while fetching table metadata', async () => {
|
|
474
|
-
const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(userCredentials);
|
|
475
|
-
const getMetadata = vi.fn();
|
|
476
|
-
vi.mocked(getMetadata).mockRejectedValue(createGaxiosError(invalidGrant));
|
|
477
|
-
bigquery_1.Dataset.prototype.table = vi.fn(() => ({ getMetadata }));
|
|
478
|
-
await expect(warehouse.getFields('myTable', 'mySchema', 'myDatabase')).rejects.toThrow(common_1.BigqueryTokenError);
|
|
479
|
-
await expect(warehouse.getCatalog(WarehouseClient_mock_1.config)).rejects.toThrow(common_1.BigqueryTokenError);
|
|
480
|
-
});
|
|
481
|
-
it('translates an invalid_grant rejection raised while listing datasets', async () => {
|
|
482
|
-
const warehouse = new BigqueryWarehouseClient_1.BigqueryWarehouseClient(userCredentials);
|
|
483
|
-
const getDatasets = vi.fn();
|
|
484
|
-
vi.mocked(getDatasets).mockRejectedValue(createGaxiosError(invalidGrant));
|
|
485
|
-
warehouse.client.getDatasets =
|
|
486
|
-
getDatasets;
|
|
487
|
-
await expect(warehouse.getAllTables()).rejects.toThrow(common_1.BigqueryTokenError);
|
|
488
|
-
});
|
|
489
|
-
it('translates an invalid_grant rejection from the connection test', async () => {
|
|
490
|
-
const warehouse = createWarehouseRejectingQueries(userCredentials, createGaxiosError(invalidGrant));
|
|
491
|
-
await expect(warehouse.test()).rejects.toThrow(common_1.BigqueryTokenError);
|
|
492
|
-
});
|
|
493
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ClickhouseWarehouseClient.test.d.ts","sourceRoot":"","sources":["../../src/warehouseClients/ClickhouseWarehouseClient.test.ts"],"names":[],"mappings":""}
|