UNPKG

@digitalwalletcorp/sql-builder

Version:
151 lines (150 loc) 5.22 kB
/** * PostgreSQL: $1, $2... 配列 * MySQL: ? 配列 * SQLite: ?, $name, :name 配列またはオブジェクト * Oracle: :name オブジェクト * SQL Server: `@name` 配列またはオブジェクト * BigQuery: `@name` オブジェクト * * 以下をサポートする * ・$1, $2 (postgres) * ・? (mysql) SQLite, SQL Serverもこれで代替可能 * ・:name (oracle) SQLiteもこれで代替可能 * ・`@name` (mssql) * ・`@name` (bigquery) */ declare const dbTypes: readonly ["postgres", "mysql", "oracle", "mssql", "bigquery"]; type BindType = typeof dbTypes[number]; type BindParameterType<T extends BindType> = T extends 'postgres' ? any[] : T extends 'mysql' ? any[] : T extends 'oracle' ? Record<string, any> : T extends 'mssql' ? Record<string, any> : undefined; /** * 動的SQLを生成する * * このクラスは、S2Daoが提供していた機能を模したもので、SQLテンプレートとバインドエンティティを渡すことで動的にSQLを生成する。 * * 例) * テンプレート * ``` * SELECT COUNT(*) AS cnt FROM activity * \/*BEGIN*\/WHERE * 1 = 1 * \/*IF projectNames.length*\/AND project_name IN \/*projectNames*\/('project1')\/*END*\/ * \/*IF nodeNames.length*\/AND node_name IN \/*nodeNames*\/('node1')\/*END*\/ * \/*IF jobNames.length*\/AND job_name IN \/*jobNames*\/('job1')\/*END*\/ * \/*IF statuses.length*\/AND status IN \/*statuses*\/(1)\/*END*\/ * \/*END*\/ * ``` * * 呼び出し * ``` * const bindEntity = { * projectNames: ['pj1', 'pj2'], * nodeNames: ['node1', 'node2'], * jobNames: ['job1', 'job2'], * statuses: [1, 2] * }; * const sql = builder.generateSQL(template, bindEntity); * ``` * * 結果 * ``` * SELECT COUNT(*) AS cnt FROM activity * WHERE * 1 = 1 * AND project_name IN ('pj1','pj2') * AND node_name IN ('node1','node2') * AND job_name IN ('job1','job2') * AND status IN (1,2) * ``` */ export declare class SQLBuilder { private REGEX_TAG_PATTERN; private bindType?; constructor(bindType?: BindType); /** * 指定したテンプレートにエンティティの値をバインドしたSQLを生成する * * @param {string} template * @param {Record<string, any>} entity * @returns {string} */ generateSQL(template: string, entity: Record<string, any>): string; /** * 指定したテンプレートにエンティティの値をバインド可能なプレースホルダー付きSQLを生成し、 * バインドパラメータと共にタプル型で返却する * * @param {string} template * @param {Record<string, any>} entity * @param {BindType} [bindType] * @returns {[string, BindParameterType<T>]} */ generateParameterizedSQL<T extends BindType>(template: string, entity: Record<string, any>, bindType?: T): [string, BindParameterType<T>]; /** * テンプレートに含まれるタグ構成を解析してコンテキストを返す * * @param {string} template * @returns {TagContext[]} */ private createTagContexts; /** * テンプレートを分析して生成したSQLを返す * * @param {SharedIndex} pos 現在処理している文字列の先頭インデックス * @param {string} template * @param {Record<string, any>} entity * @param {TagContext[]} tagContexts * @param {*} [options] * ├ bindType BindType * ├ bindIndex number * ├ bindParams BindParameterType<T> * @returns {string} */ private parse; /** * ダミーパラメータの終了インデックスを返す * * @param {string} template * @param {TagContext} tagContext * @returns {number} */ private getDummyParamEndIndex; /** * IF条件が成立するか判定する * * @param {string} condition `params.length`や`param === 'a'`などの条件式 * @param {Record<string, any>} entity * @returns {boolean} */ private evaluateCondition; /** * entityからparamで指定した値を文字列で取得する * entityの値がstringの場合、SQLインジェクションの危険のある文字はエスケープする * * * 返却する値が配列の場合は丸括弧で括り、各項目をカンマで区切る * ('a', 'b', 'c') * (1, 2, 3) * * 返却する値がstring型の場合はシングルクォートで括る * 'abc' * * 返却する値がnumber型の場合はそのまま返す * 1234 * * 返却する値がboolean型の場合はそのまま返す * true * false * * @param {string} property `obj.param1.param2`などのドットで繋いだプロパティ * @param {Record<string, any>} entity * @param {*} [options] * ├ responseType 'string' | 'array' | 'object' * @returns {string} */ private extractValue; /** * SQLインジェクション対策 * * シングルクォートのエスケープ * * バックスラッシュのエスケープ * * @param {string} str * @returns {string} */ private escape; } export {};