{"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 © BeeAI a Series of LF Projects, LLC\n * SPDX-License-Identifier: Apache-2.0\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"]}