{"version":3,"sources":["../../../src/tools/database/sql.ts"],"names":["SQLToolAction","GetMetadata","Query","SQLToolOutput","JSONToolOutput","SQLTool","Tool","name","description","inputSchema","z","object","action","nativeEnum","describe","query","string","optional","emitter","Emitter","root","child","namespace","creator","options","connection","dialect","ValidationError","message","propertyName","schema","provider","storage","validateInput","input","ToolInputValidationError","register","sequelize","Sequelize","authenticate","error","ToolError","isRetryable","isFatal","_run","_options","metadata","getMetadata","executeQuery","isReadOnlyQuery","success","results","Array","isArray","length","schemaHint","errorMessage","normalizedQuery","trim","toUpperCase","startsWith","destroy","cache","Cache","getInstance","entry","get","clear","data","close"],"mappings":"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","file":"sql.cjs","sourcesContent":["/**\n * Copyright 2025 IBM Corp.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n  Tool,\n  ToolInput,\n  ToolError,\n  BaseToolOptions,\n  BaseToolRunOptions,\n  JSONToolOutput,\n  ToolInputValidationError,\n  ToolEmitter,\n} from \"@/tools/base.js\";\nimport { z } from \"zod\";\nimport { Sequelize, Options } from \"sequelize\";\nimport { Provider, getMetadata } from \"@/tools/database/metadata.js\";\nimport { Cache } from \"@/cache/decoratorCache.js\";\nimport { ValidationError } from \"ajv\";\nimport { AnyToolSchemaLike } from \"@/internals/helpers/schema.js\";\nimport { Emitter } from \"@/emitter/emitter.js\";\n\ninterface ToolOptions extends BaseToolOptions {\n  provider: Provider;\n  connection: Options;\n}\n\ntype ToolRunOptions = BaseToolRunOptions;\n\nexport const SQLToolAction = {\n  GetMetadata: \"GET_METADATA\",\n  Query: \"QUERY\",\n} as const;\n\nexport class SQLToolOutput extends JSONToolOutput<any> {}\n\nexport class SQLTool extends Tool<SQLToolOutput, ToolOptions, ToolRunOptions> {\n  name = \"SQLTool\";\n\n  description = `Converts natural language to SQL query and executes it. IMPORTANT: strictly follow this order of actions:\n   1. ${SQLToolAction.GetMetadata} - get database tables structure (metadata)\n   2. ${SQLToolAction.Query} - execute the generated SQL query`;\n\n  inputSchema() {\n    return z.object({\n      action: z\n        .nativeEnum(SQLToolAction)\n        .describe(\n          `The action to perform. ${SQLToolAction.GetMetadata} get database tables structure, ${SQLToolAction.Query} execute the SQL query`,\n        ),\n      query: z\n        .string()\n        .optional()\n        .describe(`The SQL query to be executed, required for ${SQLToolAction.Query} action`),\n    });\n  }\n\n  public readonly emitter: ToolEmitter<ToolInput<this>, SQLToolOutput> = Emitter.root.child({\n    namespace: [\"tool\", \"database\", \"sql\"],\n    creator: this,\n  });\n\n  public constructor(options: ToolOptions) {\n    super(options);\n    if (!options.connection.dialect) {\n      throw new ValidationError([\n        {\n          message: \"Property is required\",\n          propertyName: \"connection.dialect\",\n        },\n      ]);\n    }\n    if (\n      !options.connection.schema &&\n      (options.provider === \"oracle\" || options.provider === \"db2\")\n    ) {\n      throw new ValidationError([\n        {\n          message: `Property is required for ${options.provider}`,\n          propertyName: \"connection.schema\",\n        },\n      ]);\n    }\n    if (!options.connection.storage && options.provider === \"sqlite\") {\n      throw new ValidationError([\n        {\n          message: `Property is required for ${options.provider}`,\n          propertyName: \"connection.storage\",\n        },\n      ]);\n    }\n  }\n\n  protected validateInput(\n    schema: AnyToolSchemaLike,\n    input: unknown,\n  ): asserts input is ToolInput<this> {\n    super.validateInput(schema, input);\n    if (input.action === SQLToolAction.Query && !input.query) {\n      throw new ToolInputValidationError(\n        `SQL Query is required for ${SQLToolAction.Query} action.`,\n      );\n    }\n  }\n\n  static {\n    this.register();\n  }\n\n  @Cache()\n  protected async connection(): Promise<Sequelize> {\n    try {\n      const sequelize = new Sequelize(this.options.connection);\n\n      await sequelize.authenticate();\n      return sequelize;\n    } catch (error) {\n      throw new ToolError(`Unable to connect to database: ${error}`, [], {\n        isRetryable: false,\n        isFatal: true,\n      });\n    }\n  }\n\n  protected async _run(\n    input: ToolInput<this>,\n    _options: Partial<ToolRunOptions>,\n  ): Promise<SQLToolOutput> {\n    const { provider, connection } = this.options;\n    const { schema } = connection;\n\n    if (input.action === SQLToolAction.GetMetadata) {\n      const sequelize = await this.connection();\n      const metadata = await getMetadata(sequelize, provider, schema);\n      return new SQLToolOutput(metadata);\n    }\n\n    if (input.action === SQLToolAction.Query) {\n      return await this.executeQuery(input.query!, provider, schema);\n    }\n\n    throw new ToolError(`Invalid action specified: ${input.action}`);\n  }\n\n  protected async executeQuery(\n    query: string,\n    provider: Provider,\n    schema: string | undefined,\n  ): Promise<SQLToolOutput> {\n    if (!this.isReadOnlyQuery(query)) {\n      return new JSONToolOutput({\n        success: false,\n        error: \"Invalid query. Only SELECT queries are allowed.\",\n      });\n    }\n\n    try {\n      const sequelize = await this.connection();\n      const [results] = await sequelize.query(query);\n      if (Array.isArray(results) && results.length > 0) {\n        return new JSONToolOutput({ success: true, results });\n      }\n\n      return new JSONToolOutput({\n        success: false,\n        message: `No rows selected`,\n      });\n    } catch (error) {\n      const schemaHint = schema\n        ? `Fully qualify the table names by appending the schema name \"${schema}\" as a prefix, for example: ${schema}.table_name`\n        : \"\";\n      const errorMessage = `Generate a correct query that retrieves data using the appropriate ${provider} dialect.\n      ${schemaHint}\n      The original request was: ${query}, and the error was: ${error.message}.`;\n      throw new ToolError(errorMessage);\n    }\n  }\n\n  private isReadOnlyQuery(query: string): boolean {\n    const normalizedQuery = query.trim().toUpperCase();\n    return (\n      normalizedQuery.startsWith(\"SELECT\") ||\n      normalizedQuery.startsWith(\"SHOW\") ||\n      normalizedQuery.startsWith(\"DESC\")\n    );\n  }\n\n  public async destroy(): Promise<void> {\n    // @ts-expect-error protected property\n    const cache = Cache.getInstance(this, \"connection\");\n    const entry = cache.get();\n\n    if (entry) {\n      cache.clear();\n\n      try {\n        await entry.data.close();\n      } catch (error) {\n        throw new ToolError(`Failed to close the database connection`, [error]);\n      }\n    }\n  }\n}\n"]}