Skip to content

Commit 0cb016b

Browse files
committed
feat(prestodb-driver, trino-driver): Support dbUseSelectTestConnection flag
With this flag set to true - use `SELECT 1` query for testing connection
1 parent 7992cae commit 0cb016b

File tree

9 files changed

+168
-4
lines changed

9 files changed

+168
-4
lines changed

.github/actions/integration/trino.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
set -eo pipefail
3+
4+
# Debug log for test containers
5+
export DEBUG=testcontainers
6+
7+
export TEST_PRESTO_VERSION=341-SNAPSHOT
8+
export TEST_PGSQL_VERSION=12.4
9+
10+
echo "::group::Trino ${TEST_PRESTO_VERSION} with PostgreSQL ${TEST_PGSQL_VERSION}"
11+
docker pull lewuathe/presto-coordinator:${TEST_PRESTO_VERSION}
12+
docker pull lewuathe/presto-worker:${TEST_PRESTO_VERSION}
13+
docker pull postgres:${TEST_PGSQL_VERSION}
14+
yarn lerna run --concurrency 1 --stream --no-prefix integration:trino
15+
echo "::endgroup::"

.github/workflows/push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ jobs:
412412
matrix:
413413
node-version: [22.x]
414414
db: [
415-
'athena', 'bigquery', 'snowflake',
415+
'athena', 'bigquery', 'snowflake', 'trino',
416416
'clickhouse', 'druid', 'elasticsearch', 'mssql', 'mysql', 'postgres', 'prestodb',
417417
'mysql-aurora-serverless', 'crate', 'mongobi', 'firebolt', 'dremio', 'vertica'
418418
]

packages/cubejs-backend-shared/src/env.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,33 @@ const variables: Record<string, (...args: any) => any> = {
337337
]
338338
),
339339

340+
/**
341+
* Use `SELECT 1` query for testConnection.
342+
* It might be used in any driver where there is a specific testConnection
343+
* like a REST call, but for some reason it's not possible to use it in
344+
* deployment environment.
345+
*/
346+
dbUseSelectTestConnection: ({
347+
dataSource,
348+
}: {
349+
dataSource: string,
350+
}) => {
351+
const val = process.env[
352+
keyByDataSource('CUBEJS_DB_USE_SELECT_TEST_CONNECTION', dataSource)
353+
] || 'false';
354+
if (val.toLocaleLowerCase() === 'true') {
355+
return true;
356+
} else if (val.toLowerCase() === 'false') {
357+
return false;
358+
} else {
359+
throw new TypeError(
360+
`The ${
361+
keyByDataSource('CUBEJS_DB_USE_SELECT_TEST_CONNECTION', dataSource)
362+
} must be either 'true' or 'false'.`
363+
);
364+
}
365+
},
366+
340367
/**
341368
* Kafka host for direct downloads from ksqlDb
342369
*/

packages/cubejs-prestodb-driver/src/PrestoDriver.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ export class PrestoDriver extends BaseDriver implements DriverInterface {
6868

6969
protected client: any;
7070

71+
protected useSelectTestConnection: boolean;
72+
7173
/**
7274
* Class constructor.
7375
*/
@@ -86,6 +88,8 @@ export class PrestoDriver extends BaseDriver implements DriverInterface {
8688
throw new Error('Both user/password and auth token are set. Please remove password or token.');
8789
}
8890

91+
this.useSelectTestConnection = getEnv('dbUseSelectTestConnection', { dataSource });
92+
8993
this.config = {
9094
host: getEnv('dbHost', { dataSource }),
9195
port: getEnv('dbPort', { dataSource }),
@@ -109,6 +113,10 @@ export class PrestoDriver extends BaseDriver implements DriverInterface {
109113
}
110114

111115
public async testConnection(): Promise<void> {
116+
if (this.useSelectTestConnection) {
117+
return this.testConnectionViaSelect();
118+
}
119+
112120
return new Promise((resolve, reject) => {
113121
// Get node list of presto cluster and return it.
114122
// @see https://prestodb.io/docs/current/rest/node.html
@@ -122,6 +130,11 @@ export class PrestoDriver extends BaseDriver implements DriverInterface {
122130
});
123131
}
124132

133+
protected async testConnectionViaSelect() {
134+
const query = SqlString.format('SELECT 1', []);
135+
await this.queryPromised(query, false);
136+
}
137+
125138
public query(query: string, values: unknown[]): Promise<any[]> {
126139
return <Promise<any[]>> this.queryPromised(this.prepareQueryWithParams(query, values), false);
127140
}

packages/cubejs-prestodb-driver/test/presto-driver.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ describe('PrestoHouseDriver', () => {
7878
// eslint-disable-next-line func-names
7979
it('should test informationSchemaQuery', async () => {
8080
await doWithDriver(async (driver: any) => {
81-
const informationSchemaQuery=driver.informationSchemaQuery();
82-
expect(informationSchemaQuery).toContain("columns.table_schema = 'sf1'");
81+
const informationSchemaQuery = driver.informationSchemaQuery();
82+
expect(informationSchemaQuery).toContain('columns.table_schema = \'sf1\'');
8383
});
8484
});
8585
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: '2.2'
2+
3+
services:
4+
coordinator:
5+
image: trinodb/trino
6+
ports:
7+
- "8080:8080"
8+
container_name: "coordinator"
9+
healthcheck:
10+
test: "trino --execute 'SELECT 1' || exit 1"
11+
interval: 10s
12+
timeout: 5s
13+
retries: 5

packages/cubejs-trino-driver/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
"build": "rm -rf dist && npm run tsc",
2222
"tsc": "tsc",
2323
"watch": "tsc -w",
24+
"integration": "jest dist/test",
25+
"integration:trino": "jest dist/test",
2426
"lint": "eslint src/* --ext .ts",
2527
"lint:fix": "eslint --fix src/* --ext .ts"
2628
},
@@ -38,7 +40,11 @@
3840
"access": "public"
3941
},
4042
"devDependencies": {
41-
"@cubejs-backend/linter": "1.3.19"
43+
"@cubejs-backend/linter": "1.3.19",
44+
"@types/jest": "^29",
45+
"jest": "^29",
46+
"testcontainers": "^10.13.0",
47+
"typescript": "~5.2.2"
4248
},
4349
"eslintConfig": {
4450
"extends": "../cubejs-linter"

packages/cubejs-trino-driver/src/TrinoDriver.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ export class TrinoDriver extends PrestoDriver {
1111
return PrestodbQuery;
1212
}
1313

14+
// eslint-disable-next-line consistent-return
1415
public override async testConnection(): Promise<void> {
16+
if (this.useSelectTestConnection) {
17+
return this.testConnectionViaSelect();
18+
}
19+
1520
const { host, port, ssl, basic_auth: basicAuth, custom_auth: customAuth } = this.config;
1621
const protocol = ssl ? 'https' : 'http';
1722
const url = `${protocol}://${host}:${port}/v1/info`;
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { TrinoDriver } from '../src/TrinoDriver';
2+
3+
const path = require('path');
4+
const { DockerComposeEnvironment, Wait } = require('testcontainers');
5+
6+
describe('TrinoDriver', () => {
7+
jest.setTimeout(6 * 60 * 1000);
8+
9+
let env: any;
10+
let config: any;
11+
12+
const doWithDriver = async (callback: any) => {
13+
const driver = new TrinoDriver(config);
14+
15+
await callback(driver);
16+
};
17+
18+
// eslint-disable-next-line consistent-return,func-names
19+
beforeAll(async () => {
20+
const authOpts = {
21+
basic_auth: {
22+
user: 'presto',
23+
password: ''
24+
}
25+
};
26+
27+
if (process.env.TEST_PRESTO_HOST) {
28+
config = {
29+
host: process.env.TEST_PRESTO_HOST || 'localhost',
30+
port: process.env.TEST_PRESTO_PORT || '8080',
31+
catalog: process.env.TEST_PRESTO_CATALOG || 'tpch',
32+
schema: 'sf1',
33+
...authOpts
34+
};
35+
36+
return;
37+
}
38+
39+
const dc = new DockerComposeEnvironment(
40+
path.resolve(path.dirname(__filename), '../../'),
41+
'docker-compose.yml'
42+
);
43+
44+
env = await dc
45+
.withStartupTimeout(240 * 1000)
46+
.withWaitStrategy('coordinator', Wait.forHealthCheck())
47+
.up();
48+
49+
config = {
50+
host: env.getContainer('coordinator').getHost(),
51+
port: env.getContainer('coordinator').getMappedPort(8080),
52+
catalog: 'tpch',
53+
schema: 'sf1',
54+
...authOpts
55+
};
56+
});
57+
58+
// eslint-disable-next-line consistent-return,func-names
59+
afterAll(async () => {
60+
if (env) {
61+
await env.down();
62+
}
63+
});
64+
65+
it('should construct', async () => {
66+
await doWithDriver(() => {
67+
//
68+
});
69+
});
70+
71+
// eslint-disable-next-line func-names
72+
it('should test connection', async () => {
73+
await doWithDriver(async (driver: any) => {
74+
await driver.testConnection();
75+
});
76+
});
77+
78+
// eslint-disable-next-line func-names
79+
it('should test informationSchemaQuery', async () => {
80+
await doWithDriver(async (driver: any) => {
81+
const informationSchemaQuery = driver.informationSchemaQuery();
82+
expect(informationSchemaQuery).toContain('columns.table_schema = \'sf1\'');
83+
});
84+
});
85+
});

0 commit comments

Comments
 (0)