From 488e0c9f511fbd96fcb47a772cfce3a926d2522c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=20Anast=C3=A1cio?= Date: Tue, 12 Nov 2024 14:41:51 -0300 Subject: [PATCH] Use the Trino client instead of inheriting from Presto --- .github/actions/smoke.sh | 8 +- .../configuration/data-sources/trino.mdx | 5 +- packages/cubejs-backend-shared/src/env.ts | 72 +++++------ .../test/db_env_multi.test.ts | 29 +++++ .../cubejs-testing/test/smoke-trino.test.ts | 2 +- .../config/catalog/postgresql.properties | 4 + .../cubejs-trino-driver/docker-compose.yml | 13 ++ packages/cubejs-trino-driver/package.json | 14 +- .../cubejs-trino-driver/src/TrinoDriver.ts | 122 +++++++++++++++++- .../test/trino-driver.test.ts | 85 ++++++++++++ yarn.lock | 47 ++++++- 11 files changed, 345 insertions(+), 56 deletions(-) create mode 100644 packages/cubejs-trino-driver/config/catalog/postgresql.properties create mode 100644 packages/cubejs-trino-driver/docker-compose.yml create mode 100644 packages/cubejs-trino-driver/test/trino-driver.test.ts diff --git a/.github/actions/smoke.sh b/.github/actions/smoke.sh index 57eceb824b904..c4bf6a7b75af5 100755 --- a/.github/actions/smoke.sh +++ b/.github/actions/smoke.sh @@ -45,9 +45,9 @@ echo "::endgroup::" #yarn lerna run --concurrency 1 --stream --no-prefix smoke:prestodb #echo "::endgroup::" -echo "::group::Trino" -yarn lerna run --concurrency 1 --stream --no-prefix smoke:trino -echo "::endgroup::" +#echo "::group::Trino" +#yarn lerna run --concurrency 1 --stream --no-prefix smoke:trino +#echo "::endgroup::" echo "::group::MS SQL" yarn lerna run --concurrency 1 --stream --no-prefix smoke:mssql @@ -55,4 +55,4 @@ echo "::endgroup::" echo "::group::MongoBI" yarn lerna run --concurrency 1 --stream --no-prefix smoke:mongobi -echo "::endgroup::" \ No newline at end of file +echo "::endgroup::" diff --git a/docs/pages/product/configuration/data-sources/trino.mdx b/docs/pages/product/configuration/data-sources/trino.mdx index 83a5f7450f689..1ac0d34129905 100644 --- a/docs/pages/product/configuration/data-sources/trino.mdx +++ b/docs/pages/product/configuration/data-sources/trino.mdx @@ -22,7 +22,7 @@ CUBEJS_DB_TYPE=trino CUBEJS_DB_HOST=my.trino.host CUBEJS_DB_USER=trino_user CUBEJS_DB_PASS=********** -CUBEJS_DB_PRESTO_CATALOG=my_trino_catalog +CUBEJS_DB_TRINO_CATALOG=my_trino_catalog CUBEJS_DB_SCHEMA=my_trino_schema ``` @@ -34,9 +34,8 @@ CUBEJS_DB_SCHEMA=my_trino_schema | `CUBEJS_DB_PORT` | The port for the database connection | A valid port number | ❌ | | `CUBEJS_DB_USER` | The username used to connect to the database | A valid database username | ✅ | | `CUBEJS_DB_PASS` | The password used to connect to the database | A valid database password | ✅ | -| `CUBEJS_DB_PRESTO_CATALOG` | The catalog within Presto to connect to | A valid catalog name within a Presto database | ✅ | +| `CUBEJS_DB_TRINO_CATALOG` | The catalog within Presto to connect to | A valid catalog name within a Presto database | ✅ | | `CUBEJS_DB_SCHEMA` | The schema within the database to connect to | A valid schema name within a Presto database | ✅ | -| `CUBEJS_DB_SSL` | If `true`, enables SSL encryption for database connections from Cube | `true`, `false` | ❌ | | `CUBEJS_CONCURRENCY` | The number of concurrent connections each queue has to the database. Default is `2` | A valid number | ❌ | | `CUBEJS_DB_MAX_POOL` | The maximum number of concurrent database connections to pool. Default is `8` | A valid number | ❌ | diff --git a/packages/cubejs-backend-shared/src/env.ts b/packages/cubejs-backend-shared/src/env.ts index a8021d303d9ad..0b0a94d2bee24 100644 --- a/packages/cubejs-backend-shared/src/env.ts +++ b/packages/cubejs-backend-shared/src/env.ts @@ -66,8 +66,7 @@ export function assertDataSource(dataSource = 'default'): string { return dataSource; } else { throw new Error( - `The ${ - dataSource + `The ${dataSource } data source is missing in the declared CUBEJS_DATASOURCES.` ); } @@ -90,10 +89,8 @@ export function keyByDataSource(origin: string, dataSource?: string): string { return `CUBEJS_DS_${dataSource.toUpperCase()}_${s[1]}`; } else { throw new Error( - `The ${ - origin - } environment variable can not be converted for the ${ - dataSource + `The ${origin + } environment variable can not be converted for the ${dataSource } data source.` ); } @@ -237,8 +234,7 @@ const variables: Record any> = { return false; } else { throw new TypeError( - `The ${ - keyByDataSource('CUBEJS_DB_SSL', dataSource) + `The ${keyByDataSource('CUBEJS_DB_SSL', dataSource) } must be either 'true' or 'false'.` ); } @@ -261,8 +257,7 @@ const variables: Record any> = { return false; } else { throw new TypeError( - `The ${ - keyByDataSource('CUBEJS_DB_SSL_REJECT_UNAUTHORIZED', dataSource) + `The ${keyByDataSource('CUBEJS_DB_SSL_REJECT_UNAUTHORIZED', dataSource) } must be either 'true' or 'false'.` ); } @@ -353,8 +348,7 @@ const variables: Record any> = { }) => ( process.env[keyByDataSource('CUBEJS_DB_PORT', dataSource)] ? parseInt( - `${ - process.env[keyByDataSource('CUBEJS_DB_PORT', dataSource)] + `${process.env[keyByDataSource('CUBEJS_DB_PORT', dataSource)] }`, 10, ) @@ -409,8 +403,7 @@ const variables: Record any> = { ]; if (required && !val) { throw new Error( - `The ${ - keyByDataSource('CUBEJS_DB_NAME', dataSource) + `The ${keyByDataSource('CUBEJS_DB_NAME', dataSource) } is required and missing.` ); } @@ -429,10 +422,8 @@ const variables: Record any> = { required?: boolean, }) => { console.warn( - `The ${ - keyByDataSource('CUBEJS_DB_SCHEMA', dataSource) - } is deprecated. Please, use the ${ - keyByDataSource('CUBEJS_DB_NAME', dataSource) + `The ${keyByDataSource('CUBEJS_DB_SCHEMA', dataSource) + } is deprecated. Please, use the ${keyByDataSource('CUBEJS_DB_NAME', dataSource) } instead.` ); const val = process.env[ @@ -440,8 +431,7 @@ const variables: Record any> = { ]; if (required && !val) { throw new Error( - `The ${ - keyByDataSource('CUBEJS_DB_SCHEMA', dataSource) + `The ${keyByDataSource('CUBEJS_DB_SCHEMA', dataSource) } is required and missing.` ); } @@ -460,10 +450,8 @@ const variables: Record any> = { required?: boolean, }) => { console.warn( - `The ${ - keyByDataSource('CUBEJS_DATABASE', dataSource) - } is deprecated. Please, use the ${ - keyByDataSource('CUBEJS_DB_NAME', dataSource) + `The ${keyByDataSource('CUBEJS_DATABASE', dataSource) + } is deprecated. Please, use the ${keyByDataSource('CUBEJS_DB_NAME', dataSource) } instead.` ); const val = process.env[ @@ -471,8 +459,7 @@ const variables: Record any> = { ]; if (required && !val) { throw new Error( - `The ${ - keyByDataSource('CUBEJS_DATABASE', dataSource) + `The ${keyByDataSource('CUBEJS_DATABASE', dataSource) } is required and missing.` ); } @@ -489,10 +476,9 @@ const variables: Record any> = { }) => ( process.env[keyByDataSource('CUBEJS_DB_MAX_POOL', dataSource)] ? parseInt( - `${ - process.env[ - keyByDataSource('CUBEJS_DB_MAX_POOL', dataSource) - ] + `${process.env[ + keyByDataSource('CUBEJS_DB_MAX_POOL', dataSource) + ] }`, 10, ) @@ -684,8 +670,7 @@ const variables: Record any> = { supported.indexOf(<'s3' | 'gcp' | 'azure'>val) === -1 ) { throw new TypeError( - `The ${ - keyByDataSource('CUBEJS_DB_EXPORT_BUCKET_TYPE', dataSource) + `The ${keyByDataSource('CUBEJS_DB_EXPORT_BUCKET_TYPE', dataSource) } must be one of the [${supported.join(', ')}].` ); } @@ -878,8 +863,7 @@ const variables: Record any> = { ]; if (!val) { throw new Error( - `The ${ - keyByDataSource('CUBEJS_DB_DATABRICKS_URL', dataSource) + `The ${keyByDataSource('CUBEJS_DB_DATABRICKS_URL', dataSource) } is required and missing.` ); } @@ -1387,11 +1371,10 @@ const variables: Record any> = { return false; } else { throw new TypeError( - `The ${ - keyByDataSource( - 'CUBEJS_DB_SNOWFLAKE_CLIENT_SESSION_KEEP_ALIVE', - dataSource, - ) + `The ${keyByDataSource( + 'CUBEJS_DB_SNOWFLAKE_CLIENT_SESSION_KEEP_ALIVE', + dataSource, + ) } must be either 'true' or 'false'.` ); } @@ -1626,6 +1609,17 @@ const variables: Record any> = { ] ), + /** + * Trino catalog. + */ + trinoCatalog: ({ + dataSource, + }: { dataSource: string }) => ( + process.env[ + keyByDataSource('CUBEJS_DB_TRINO_CATALOG', dataSource) + ] + ), + /** **************************************************************** * Cube Store Driver * ***************************************************************** */ diff --git a/packages/cubejs-backend-shared/test/db_env_multi.test.ts b/packages/cubejs-backend-shared/test/db_env_multi.test.ts index 1eb8596024f7e..f30197f8cc146 100644 --- a/packages/cubejs-backend-shared/test/db_env_multi.test.ts +++ b/packages/cubejs-backend-shared/test/db_env_multi.test.ts @@ -2189,4 +2189,33 @@ describe('Multiple datasources', () => { 'The wrong data source is missing in the declared CUBEJS_DATASOURCES.' ); }); + + test('getEnv("trinoCatalog")', () => { + process.env.CUBEJS_DB_TRINO_CATALOG = 'default1'; + process.env.CUBEJS_DS_POSTGRES_DB_TRINO_CATALOG = 'postgres1'; + process.env.CUBEJS_DS_WRONG_DB_TRINO_CATALOG = 'wrong1'; + expect(getEnv('trinoCatalog', { dataSource: 'default' })).toEqual('default1'); + expect(getEnv('trinoCatalog', { dataSource: 'postgres' })).toEqual('postgres1'); + expect(() => getEnv('trinoCatalog', { dataSource: 'wrong' })).toThrow( + 'The wrong data source is missing in the declared CUBEJS_DATASOURCES.' + ); + + process.env.CUBEJS_DB_TRINO_CATALOG = 'default2'; + process.env.CUBEJS_DS_POSTGRES_DB_TRINO_CATALOG = 'postgres2'; + process.env.CUBEJS_DS_WRONG_DB_TRINO_CATALOG = 'wrong2'; + expect(getEnv('trinoCatalog', { dataSource: 'default' })).toEqual('default2'); + expect(getEnv('trinoCatalog', { dataSource: 'postgres' })).toEqual('postgres2'); + expect(() => getEnv('trinoCatalog', { dataSource: 'wrong' })).toThrow( + 'The wrong data source is missing in the declared CUBEJS_DATASOURCES.' + ); + + delete process.env.CUBEJS_DB_TRINO_CATALOG; + delete process.env.CUBEJS_DS_POSTGRES_DB_TRINO_CATALOG; + delete process.env.CUBEJS_DS_WRONG_DB_TRINO_CATALOG; + expect(getEnv('trinoCatalog', { dataSource: 'default' })).toBeUndefined(); + expect(getEnv('trinoCatalog', { dataSource: 'postgres' })).toBeUndefined(); + expect(() => getEnv('trinoCatalog', { dataSource: 'wrong' })).toThrow( + 'The wrong data source is missing in the declared CUBEJS_DATASOURCES.' + ); + }); }); diff --git a/packages/cubejs-testing/test/smoke-trino.test.ts b/packages/cubejs-testing/test/smoke-trino.test.ts index dab495ce45d78..309ea79d0b1ee 100644 --- a/packages/cubejs-testing/test/smoke-trino.test.ts +++ b/packages/cubejs-testing/test/smoke-trino.test.ts @@ -24,7 +24,7 @@ describe('trino', () => { CUBEJS_DB_HOST: db.getHost(), CUBEJS_DB_PORT: `${db.getMappedPort(8080)}`, - CUBEJS_DB_PRESTO_CATALOG: 'memory', + CUBEJS_DB_TRINO_CATALOG: 'memory', CUBEJS_DB_USER: 'test', ...DEFAULT_CONFIG, diff --git a/packages/cubejs-trino-driver/config/catalog/postgresql.properties b/packages/cubejs-trino-driver/config/catalog/postgresql.properties new file mode 100644 index 0000000000000..76544145684c9 --- /dev/null +++ b/packages/cubejs-trino-driver/config/catalog/postgresql.properties @@ -0,0 +1,4 @@ +connector.name=postgresql +connection-url=jdbc:postgresql://postgres:5432/trino +connection-user=trino +connection-password=9bee2c3975024292eff5829526722ac2 diff --git a/packages/cubejs-trino-driver/docker-compose.yml b/packages/cubejs-trino-driver/docker-compose.yml new file mode 100644 index 0000000000000..5a8497cc5ee32 --- /dev/null +++ b/packages/cubejs-trino-driver/docker-compose.yml @@ -0,0 +1,13 @@ +version: '2.2' + +services: + coordinator: + image: trinodb/trino + ports: + - "8080:8080" + container_name: "coordinator" + healthcheck: + test: "trino --execute 'SELECT 1' || exit 1" + interval: 10s + timeout: 5s + retries: 5 diff --git a/packages/cubejs-trino-driver/package.json b/packages/cubejs-trino-driver/package.json index ced31abc0195f..fa84544159941 100644 --- a/packages/cubejs-trino-driver/package.json +++ b/packages/cubejs-trino-driver/package.json @@ -21,6 +21,8 @@ "build": "rm -rf dist && npm run tsc", "tsc": "tsc", "watch": "tsc -w", + "integration": "npm run integration:trino", + "integration:trino": "jest --verbose --config=jest.config.js dist/test", "lint": "eslint src/* --ext .ts", "lint:fix": "eslint --fix src/* --ext .ts" }, @@ -29,7 +31,7 @@ "@cubejs-backend/prestodb-driver": "1.1.4", "@cubejs-backend/schema-compiler": "1.1.4", "@cubejs-backend/shared": "1.1.4", - "presto-client": "^0.12.2", + "trino-client": "^0.2.3", "sqlstring": "^2.3.1" }, "license": "Apache-2.0", @@ -37,7 +39,15 @@ "access": "public" }, "devDependencies": { - "@cubejs-backend/linter": "^1.0.0" + "@cubejs-backend/linter": "^1.0.0", + "@types/jest": "^27", + "jest": "^27", + "babel-jest": "^27", + "testcontainers": "^10.10.4", + "typescript": "~5.2.2" + }, + "jest": { + "testEnvironment": "node" }, "eslintConfig": { "extends": "../cubejs-linter" diff --git a/packages/cubejs-trino-driver/src/TrinoDriver.ts b/packages/cubejs-trino-driver/src/TrinoDriver.ts index bed221ac33342..f3de67e5eea19 100644 --- a/packages/cubejs-trino-driver/src/TrinoDriver.ts +++ b/packages/cubejs-trino-driver/src/TrinoDriver.ts @@ -1,9 +1,123 @@ -import { PrestoDriver } from '@cubejs-backend/prestodb-driver'; +import { + DriverInterface, + StreamOptions, + StreamTableData, + BaseDriver, + DownloadQueryResultsOptions, + DownloadQueryResultsResult, +} from '@cubejs-backend/base-driver'; +import { + getEnv, + assertDataSource, +} from '@cubejs-backend/shared'; + +import SqlString from 'sqlstring'; +import { Trino, BasicAuth, QueryData } from 'trino-client'; import { PrestodbQuery } from '@cubejs-backend/schema-compiler/dist/src/adapter/PrestodbQuery'; +import { Readable } from 'stream'; + +export type TrinoDriverConfiguration = { + server?: string; + catalog?: string; + schema?: string; + auth?: BasicAuth; + dataSource?: string; +}; + +export class TrinoDriver extends BaseDriver implements DriverInterface { + public static getDefaultConcurrency() { + return 2; + } + + protected readonly config: TrinoDriverConfiguration; + + protected readonly client: Trino; + + public constructor(config: TrinoDriverConfiguration = {}) { + super(); + + const dataSource = config.dataSource || assertDataSource('default'); + + this.config = { + server: getEnv('dbHost', { dataSource }), + catalog: + getEnv('trinoCatalog', { dataSource }) || + getEnv('dbCatalog', { dataSource }), + schema: + getEnv('dbName', { dataSource }) || + getEnv('dbSchema', { dataSource }), + auth: getEnv('dbPass', { dataSource }) ? + new BasicAuth(getEnv('dbUser', { dataSource }), getEnv('dbPass', { dataSource })) : + undefined, + ...config, + }; + + this.client = Trino.create(this.config); + } + + public async testConnection(): Promise { + const query = SqlString.format('SHOW SCHEMAS FROM ?', [this.config.catalog]); + + const schemas = await this.query(query, []); + if (schemas.length === 0) { + throw new Error(`Catalog not found: '${this.config.catalog}'`); + } + } + + public prepareQuery(query: string, values: unknown[]): string { + return SqlString.format( + query, + (values || []).map((value) => (typeof value === 'string' + ? { + toSqlString: () => SqlString.escape(value).replace(/\\\\([_%])/g, '\\$1'), + } + : value)) + ); + } + + public async query(query: string, values: unknown[]): Promise { + const preparedQuery = this.prepareQuery(query, values); + const iterator = await this.client.query(preparedQuery); + + const data: any[] = []; + + for await (const result of iterator) { + if (result.data) { + data.push(...result.data); + } + } + + return data; + } + + public async stream( + query: string, + values: unknown[], + _options: StreamOptions + ): Promise { + const preparedQuery = this.prepareQuery(query, values); + const iterator = await this.client.query(preparedQuery); + + const rowStream = Readable.from( + await iterator + .map(r => r.data ?? []) + .fold([], (row, acc) => [...acc, ...row]) + ); + + return { + rowStream, + }; + } -export class TrinoDriver extends PrestoDriver { - public constructor(options: any) { - super({ ...options, engine: 'trino' }); + public downloadQueryResults( + query: string, + values: unknown[], + options: DownloadQueryResultsOptions + ): Promise { + if (options.streamImport) { + return this.stream(query, values, options) as Promise; + } + return super.downloadQueryResults(query, values, options); } public static dialectClass() { diff --git a/packages/cubejs-trino-driver/test/trino-driver.test.ts b/packages/cubejs-trino-driver/test/trino-driver.test.ts new file mode 100644 index 0000000000000..192a5ec8653fe --- /dev/null +++ b/packages/cubejs-trino-driver/test/trino-driver.test.ts @@ -0,0 +1,85 @@ +import { TrinoDriver } from '../src/TrinoDriver'; + +const path = require('path'); +const { DockerComposeEnvironment, Wait } = require('testcontainers'); + +describe('PrestoHouseDriver', () => { + jest.setTimeout(6 * 60 * 1000); + + let env: any; + let config: any; + + const doWithDriver = async (callback: any) => { + const driver = new TrinoDriver(config); + + await callback(driver); + }; + + // eslint-disable-next-line consistent-return,func-names + beforeAll(async () => { + const authOpts = { + basic_auth: { + user: 'trino', + password: '' + } + }; + + if (process.env.TEST_PRESTO_HOST) { + config = { + host: process.env.TEST_PRESTO_HOST || 'localhost', + port: process.env.TEST_PRESTO_PORT || '8080', + catalog: process.env.TEST_PRESTO_CATALOG || 'tpch', + schema: 'sf1', + ...authOpts + }; + + return; + } + + const dc = new DockerComposeEnvironment( + path.resolve(path.dirname(__filename), '../../'), + 'docker-compose.yml' + ); + + env = await dc + .withStartupTimeout(240 * 1000) + .withWaitStrategy('coordinator', Wait.forHealthCheck()) + .up(); + + config = { + host: env.getContainer('coordinator').getHost(), + port: env.getContainer('coordinator').getMappedPort(8080), + catalog: 'tpch', + schema: 'sf1', + ...authOpts + }; + }); + + // eslint-disable-next-line consistent-return,func-names + afterAll(async () => { + if (env) { + await env.down(); + } + }); + + it('should construct', async () => { + await doWithDriver(() => { + // + }); + }); + + // eslint-disable-next-line func-names + it('should test connection', async () => { + await doWithDriver(async (driver: any) => { + await driver.testConnection(); + }); + }); + + // eslint-disable-next-line func-names + it('should test informationSchemaQuery', async () => { + await doWithDriver(async (driver: any) => { + const informationSchemaQuery = driver.informationSchemaQuery(); + expect(informationSchemaQuery).toContain("columns.table_schema = 'sf1'"); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 52b737c54400a..1dc7015c55be4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11488,6 +11488,15 @@ axe-core@^4.3.5: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA== +axios@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" + integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axios@^0.21.1: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" @@ -27215,7 +27224,7 @@ string-length@^5.0.1: char-regex "^2.0.0" strip-ansi "^7.0.1" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -27233,6 +27242,15 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -27331,7 +27349,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -27359,6 +27377,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -28248,6 +28273,13 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== +trino-client@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/trino-client/-/trino-client-0.2.3.tgz#ef7f37f89280c3dccbd8228122d2534023648274" + integrity sha512-zIHFR+rV6hL1g/dlgFzE1JCeBLNtmHphf+K6hRfu4NK4n3BdBPEcajgKGj/1Z7jyka3hBdcsB83P/ql39CQatQ== + dependencies: + axios "1.7.2" + triple-beam@^1.2.0, triple-beam@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" @@ -29675,7 +29707,7 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -29710,6 +29742,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"