-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feat(wren-ui): support generate wren sql from dialect sql #1539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a66cd78
2a02c5b
6d554c9
827b45f
a0dd596
d7c2893
2b252ae
b2f29f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,9 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| toIbisConnectionInfo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| toMultipleIbisConnectionInfos, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '../dataSource'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { DialectSQL, WrenSQL } from '../models/adaptor'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export type { WrenSQL }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const logger = getLogger('IbisAdaptor'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.level = 'debug'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -90,6 +93,7 @@ const dataSourceUrlMap: Record<SupportedDataSource, string> = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [SupportedDataSource.CLICK_HOUSE]: 'clickhouse', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [SupportedDataSource.TRINO]: 'trino', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface TableResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tables: CompactTable[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -114,11 +118,13 @@ export interface IbisQueryOptions extends IbisBaseOptions { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface IbisDryPlanOptions { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dataSource: DataSourceName; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mdl: Manifest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO: replace sql type with WrenSQL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sql: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface IIbisAdaptor { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| query: ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO: replace query type with WrenSQL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| query: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| options: IbisQueryOptions, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) => Promise<IbisQueryResponse>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -140,6 +146,16 @@ export interface IIbisAdaptor { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mdl: Manifest, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parameters: Record<string, any>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) => Promise<ValidationResponse>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| modelSubstitute: ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sql: DialectSQL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| options: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dataSource: DataSourceName; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| connectionInfo: WREN_AI_CONNECTION_INFO; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mdl: Manifest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| catalog?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| schema?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) => Promise<WrenSQL>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface IbisResponse { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -162,6 +178,7 @@ enum IBIS_API_TYPE { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| METADATA = 'METADATA', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VALIDATION = 'VALIDATION', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ANALYSIS = 'ANALYSIS', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MODEL_SUBSTITUTE = 'MODEL_SUBSTITUTE', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export class IbisAdaptor implements IIbisAdaptor { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -183,11 +200,8 @@ export class IbisAdaptor implements IIbisAdaptor { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Got error when dry plan with ibis: ${e.response.data}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw Errors.create(Errors.GeneralErrorCodes.DRY_PLAN_ERROR, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customMessage: e.response.data, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| originalError: e, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Dry plan error: ${e.response?.data || e.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.throwError(e, 'Error during dry plan execution'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -219,19 +233,8 @@ export class IbisAdaptor implements IIbisAdaptor { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processTime: res.headers['x-process-time'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Got error when querying ibis: ${e.response?.data || e.message}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw Errors.create(Errors.GeneralErrorCodes.IBIS_SERVER_ERROR, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customMessage: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.response?.data || e.message || 'Error querying ibis server', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| originalError: e, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| other: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| correlationId: e.response?.headers['x-correlation-id'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processTime: e.response?.headers['x-process-time'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Query error: ${e.response?.data || e.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.throwError(e, 'Error querying ibis server'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -259,15 +262,8 @@ export class IbisAdaptor implements IIbisAdaptor { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processTime: response.headers['x-process-time'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info(`Got error when dry running ibis`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw Errors.create(Errors.GeneralErrorCodes.DRY_RUN_ERROR, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customMessage: err.response?.data || err.message, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| originalError: err, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| other: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| correlationId: err.response?.headers['x-correlation-id'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processTime: err.response?.headers['x-process-time'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Dry run error: ${err.response?.data || err.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.throwError(err, 'Error during dry run execution'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -310,16 +306,8 @@ export class IbisAdaptor implements IIbisAdaptor { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await getTablesByConnectionInfo(ibisConnectionInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Got error when getting table: ${e.response?.data || e.message}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw Errors.create(Errors.GeneralErrorCodes.IBIS_SERVER_ERROR, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customMessage: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.response?.data || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.message || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Error getting table from ibis server', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| originalError: e, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Get tables error: ${e.response?.data || e.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.throwError(e, 'Error getting table from ibis server'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -340,17 +328,8 @@ export class IbisAdaptor implements IIbisAdaptor { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Got error when getting constraint: ${e.response?.data || e.message}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw Errors.create(Errors.GeneralErrorCodes.IBIS_SERVER_ERROR, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customMessage: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.response?.data || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.message || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Error getting constraint from ibis server', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| originalError: e, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Get constraints error: ${e.response?.data || e.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.throwError(e, 'Error getting constraint from ibis server'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -375,12 +354,54 @@ export class IbisAdaptor implements IIbisAdaptor { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { valid: true, message: null }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Validation error: ${e.response?.data || e.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { valid: false, message: e.response?.data || e.message }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+357
to
+361
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Inconsistent error handling approach in validate method. The validate method returns an error response instead of throwing exceptions, which is inconsistent with other methods that use the throwError function. Consider making the error handling approach consistent across all methods. public async validate(
dataSource: DataSourceName,
validationRule: ValidationRules,
connectionInfo: WREN_AI_CONNECTION_INFO,
mdl: Manifest,
parameters: Record<string, any>,
): Promise<ValidationResponse> {
connectionInfo = this.updateConnectionInfo(connectionInfo);
const ibisConnectionInfo = toIbisConnectionInfo(dataSource, connectionInfo);
const body = {
connectionInfo: ibisConnectionInfo,
manifestStr: Buffer.from(JSON.stringify(mdl)).toString('base64'),
parameters,
};
try {
logger.debug(`Run validation rule "${validationRule}" with ibis`);
await axios.post(
`${this.ibisServerEndpoint}/${this.getIbisApiVersion(IBIS_API_TYPE.VALIDATION)}/connector/${dataSourceUrlMap[dataSource]}/validate/${snakeCase(validationRule)}`,
body,
);
return { valid: true, message: null };
- } catch (e) {
- logger.debug(`Validation error: ${e.response?.data || e.message}`);
- return { valid: false, message: e.response?.data || e.message };
- }
+ } catch (e) {
+ logger.debug(`Validation error: ${e.response?.data || e.message}`);
+ // Either convert all methods to return errors like this, or make this one throw like the others
+ return { valid: false, message: e.response?.data || e.message };
+ }
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async modelSubstitute( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sql: DialectSQL, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| options: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dataSource: DataSourceName; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| connectionInfo: WREN_AI_CONNECTION_INFO; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mdl: Manifest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| catalog?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| schema?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<WrenSQL> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { dataSource, mdl, catalog, schema } = options; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let connectionInfo = options.connectionInfo; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| connectionInfo = this.updateConnectionInfo(connectionInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const headers = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'X-User-CATALOG': catalog, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'X-User-SCHEMA': schema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ibisConnectionInfo = toIbisConnectionInfo(dataSource, connectionInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const body = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sql, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| connectionInfo: ibisConnectionInfo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| manifestStr: Buffer.from(JSON.stringify(mdl)).toString('base64'), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(`Running model substitution with ibis`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const res = await axios.post( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `${this.ibisServerEndpoint}/${this.getIbisApiVersion(IBIS_API_TYPE.MODEL_SUBSTITUTE)}/connector/${dataSourceUrlMap[dataSource]}/model-substitute`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| headers, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.data as WrenSQL; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Got error when validating connection: ${e.response?.data || e.message}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Model substitution error: ${e.response?.data || e.message}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.throwError( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Error running model substitution with ibis server', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.modelSubstituteErrorMessageBuilder, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { valid: false, message: e.response?.data || e.message }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -437,8 +458,55 @@ export class IbisAdaptor implements IIbisAdaptor { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IBIS_API_TYPE.DRY_RUN, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IBIS_API_TYPE.DRY_PLAN, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IBIS_API_TYPE.VALIDATION, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IBIS_API_TYPE.MODEL_SUBSTITUTE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ].includes(apiType); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (useV3) logger.debug('Using ibis v3 api'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return useV3 ? 'v3' : 'v2'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private throwError( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e: any, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultMessage: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| errorMessageBuilder?: CallableFunction, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const customMessage = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.response?.data?.message || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.response?.data || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| e.message || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultMessage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw Errors.create(Errors.GeneralErrorCodes.IBIS_SERVER_ERROR, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customMessage: errorMessageBuilder | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? errorMessageBuilder(customMessage) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : customMessage, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| originalError: e, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| other: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| correlationId: e.response?.headers['x-correlation-id'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processTime: e.response?.headers['x-process-time'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private modelSubstituteErrorMessageBuilder(message: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ModelSubstituteErrorEnum = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MODEL_NOT_FOUND: () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return message.includes('Model not found'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PARSING_EXCEPTION: () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return message.includes('sql.parser.ParsingException'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (ModelSubstituteErrorEnum.MODEL_NOT_FOUND()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const modelName = message.split(': ')[1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `. Try to add catalog and schema in front of your table. eg: my_database.public.${modelName}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (ModelSubstituteErrorEnum.PARSING_EXCEPTION()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '. Please check your selected column and make sure its quoted for columns with non-alphanumeric characters.' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return message; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify DialectSQL scalar type implementation.
This hook correctly uses the mutation with the new DialectSQL scalar type. Make sure the scalar implementation correctly validates the input SQL to prevent security issues like SQL injection.
🏁 Script executed:
Length of output: 84758
Verify SQL scalar security and validation
The
DialectSQLScalarinwren-ui/src/apollo/server/scalars.tscurrently only checks for a string type and does not enforce any SQL syntax validation or sanitization. As a result, malicious payloads could reach your resolver and AI adaptor unfiltered. To mitigate injection risks, please:DialectSQLScalar(or upstream input handling) to parse and validate the SQL string (e.g. with a safe‑SQL parser or whitelist of allowed statements).modelSubstituteresolver inwren-ui/src/apollo/server/resolvers/sqlPairResolver.tscalls your existingvalidateSqllogic before forwarding the query.