@digitalwalletcorp/sql-builder
Version:
This is a library for building SQL
152 lines (151 loc) • 5.29 kB
TypeScript
/**
* PostgreSQL: $1, $2... 配列
* MySQL: ? 配列
* SQLite: ?, $name, :name 配列またはオブジェクト
* Oracle: :name オブジェクト
* SQL Server: `@name` 配列またはオブジェクト
*
* 以下をサポートする
* ・$1, $2 (postgres)
* ・? (mysql) SQLite, SQL Serverもこれで代替可能
* ・:name (oracle) SQLiteもこれで代替可能
* ・`@name` (mssql)
*/
declare const dbTypes: readonly ["postgres", "mysql", "oracle", "mssql"];
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
* * null/undefinedの場合は'NULL'を返す
*
* NULLの扱いを含むため、この関数はgenerateSQLのみで利用する
*
* @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 {};