@digitalwalletcorp/sql-builder 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -234,6 +234,49 @@ Parameters: [ 123, 'project_a', 'project_b' ]
234
234
  | Bind Variable | `/*variable*/` | Binds a value from the `entity`. It automatically formats values: strings are quoted (`'value'`), numbers are left as is (`123`), and arrays are turned into comma-separated lists in parentheses (`('a','b',123)`). |
235
235
  | END | `/*END*/` | Marks the end of an `IF`, `BEGIN`, or `FOR` block. |
236
236
 
237
+ ---
238
+ ### 💡 Supported Property Paths
239
+
240
+ For `/*variable*/` (Bind Variable) tags and the `collection` part of `/*FOR item:collection*/` tags, you can specify a path to access properties within the `entity` object.
241
+
242
+ * **Syntax:** `propertyName`, `nested.property`.
243
+ * **Supported:** Direct property access (e.g., `user.id`, `order.items.length`).
244
+ * **Unsupported:** Function calls (e.g., `user.name.trim()`, `order.items.map(...)`) or any complex JavaScript expressions.
245
+
246
+ **Example:**
247
+
248
+ * **Valid Expression:** `/*userId*/` (accesses `entity.userId` as simple property)
249
+ * **Valid Expression:** `/*items*/` (accesses `entity.items` as array)
250
+ * **Invalid Expression:** `/*userId.slice(0, 10)*/` (Function call)
251
+ * **Invalid Expression:** `/*items.filter(...)*/` (Function call)
252
+
253
+ ---
254
+
255
+ ### 💡 Supported `IF` Condition Syntax
256
+
257
+ The `condition` inside an `/*IF ...*/` tag is evaluated as a JavaScript expression against the `entity` object. To ensure security and maintain simplicity, only a **limited subset of JavaScript syntax** is supported.
258
+
259
+ **Supported Operations:**
260
+
261
+ * **Entity Property Access:** You can reference properties from the `entity` object (e.g., `propertyName`, `nested.property`).
262
+ * **Object Property Access:** Access the `length`, `size` or other property of object (e.g., `String.length`, `Array.length`, `Set.size`, `Map.size`).
263
+ * **Comparison Operators:** `==`, `!=`, `===`, `!==`, `<`, `<=`, `>`, `>=`
264
+ * **Logical Operators:** `&&` (AND), `||` (OR), `!` (NOT)
265
+ * **Literals:** Numbers (`123`, `0.5`), Booleans (`true`, `false`), `null`, `undefined`, and string literals (`'value'`, `"value"`).
266
+ * **Parentheses:** `()` for grouping expressions.
267
+
268
+ **Unsupported Operations (and will cause an error if used):**
269
+
270
+ * **Function Calls:** You **cannot** call functions on properties (e.g., `user.name.startsWith('A')`, `array.map(...)`).
271
+
272
+ **Example:**
273
+
274
+ * **Valid Condition:** `user.age > 18 && user.name.length > 0 && user.id != null`
275
+ * **Invalid Condition:** `user.name.startsWith('A')` (Function call)
276
+ * **Invalid Condition:** `user.role = 'admin'` (Assignment)
277
+
278
+ ---
279
+
237
280
  ## 📜 License
238
281
 
239
282
  This project is licensed under the MIT License. See the [LICENSE](https://opensource.org/licenses/MIT) file for details.
@@ -0,0 +1,62 @@
1
+ type Token = {
2
+ type: 'IDENTIFIER';
3
+ value: string;
4
+ } | {
5
+ type: 'OPERATOR';
6
+ value: string;
7
+ } | {
8
+ type: 'NUMBER';
9
+ value: number;
10
+ } | {
11
+ type: 'BOOLEAN';
12
+ value: boolean;
13
+ } | {
14
+ type: 'STRING';
15
+ value: string;
16
+ } | {
17
+ type: 'NULL';
18
+ value: null;
19
+ } | {
20
+ type: 'UNDEFINED';
21
+ value: undefined;
22
+ } | {
23
+ type: 'PARENTHESIS';
24
+ value: '(' | ')';
25
+ };
26
+ /**
27
+ * SQLBuilderの条件文(*IF*)で指定された条件文字列を解析するためのAST。
28
+ * JavaScriptの文法をカバーするものではなく、SQLBuilderで利用可能な限定的な構文のみサポートする。
29
+ */
30
+ export declare class AbstractSyntaxTree {
31
+ /**
32
+ * 与えられた条件文字列を構文解析し、entityに対する条件として成立するか評価する
33
+ *
34
+ * @param {string} condition "params != null && params.length > 10" のような条件
35
+ * @param {Record<string, any>} entity
36
+ * @returns {boolean}
37
+ */
38
+ evaluateCondition(condition: string, entity: Record<string, any>): boolean;
39
+ /**
40
+ * 与えられた条件文字列をトークンに分割する
41
+ *
42
+ * @param {string} condition
43
+ * @returns {Token[]}
44
+ */
45
+ tokenize(condition: string): Token[];
46
+ /**
47
+ * Shunting Yardアルゴリズムで構文を逆ポーランド記法(Reverse Polish Notation)に変換する
48
+ *
49
+ * @param {Token[]} tokens
50
+ * @returns {Token[]}
51
+ */
52
+ private shuntingYard;
53
+ /**
54
+ * 逆ポーランド記法(Reverse Polish Notation)のトークンを評価する
55
+ *
56
+ * @param {Token[]} rpnTokens
57
+ * @param {Record<string, any>} entity
58
+ * @returns {boolean}
59
+ */
60
+ private evaluateRpn;
61
+ }
62
+ export {};
@@ -0,0 +1,347 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AbstractSyntaxTree = void 0;
37
+ const common = __importStar(require("./common"));
38
+ // 演算子の優先順位と結合性 (より長い演算子を先に定義)
39
+ const PRECEDENCE = {
40
+ '||': { precedence: 1, associativity: 'left' },
41
+ '&&': { precedence: 2, associativity: 'left' },
42
+ '==': { precedence: 3, associativity: 'left' },
43
+ '!=': { precedence: 3, associativity: 'left' },
44
+ '===': { precedence: 3, associativity: 'left' },
45
+ '!==': { precedence: 3, associativity: 'left' },
46
+ '<': { precedence: 4, associativity: 'left' },
47
+ '<=': { precedence: 4, associativity: 'left' },
48
+ '>': { precedence: 4, associativity: 'left' },
49
+ '>=': { precedence: 4, associativity: 'left' },
50
+ '!': { precedence: 5, associativity: 'right' } // 単項演算子は高優先度
51
+ };
52
+ /**
53
+ * SQLBuilderの条件文(*IF*)で指定された条件文字列を解析するためのAST。
54
+ * JavaScriptの文法をカバーするものではなく、SQLBuilderで利用可能な限定的な構文のみサポートする。
55
+ */
56
+ class AbstractSyntaxTree {
57
+ /**
58
+ * 与えられた条件文字列を構文解析し、entityに対する条件として成立するか評価する
59
+ *
60
+ * @param {string} condition "params != null && params.length > 10" のような条件
61
+ * @param {Record<string, any>} entity
62
+ * @returns {boolean}
63
+ */
64
+ evaluateCondition(condition, entity) {
65
+ try {
66
+ const tokens = this.tokenize(condition); // トークン化
67
+ const rpnTokens = this.shuntingYard(tokens); // RPN変換
68
+ const result = this.evaluateRpn(rpnTokens, entity); // 評価
69
+ return result;
70
+ }
71
+ catch (error) {
72
+ console.error('Error evaluating condition:', condition, entity, error);
73
+ throw error;
74
+ }
75
+ }
76
+ /**
77
+ * 与えられた条件文字列をトークンに分割する
78
+ *
79
+ * @param {string} condition
80
+ * @returns {Token[]}
81
+ */
82
+ tokenize(condition) {
83
+ const tokens = [];
84
+ let i = 0;
85
+ while (i < condition.length) {
86
+ const char = condition[i];
87
+ // 空白をスキップ
88
+ if (/\s/.test(char)) {
89
+ i++;
90
+ continue;
91
+ }
92
+ // 演算子 (長いものからチェック)
93
+ // 3桁定義
94
+ const chunk3 = condition.substring(i, i + 3);
95
+ switch (chunk3) {
96
+ case '===':
97
+ case '!==':
98
+ tokens.push({ type: 'OPERATOR', value: chunk3 });
99
+ i += 3;
100
+ continue;
101
+ default:
102
+ }
103
+ // 2桁定義
104
+ const chunk2 = condition.substring(i, i + 2);
105
+ switch (chunk2) {
106
+ case '==':
107
+ case '!=':
108
+ case '<=':
109
+ case '>=':
110
+ case '&&':
111
+ case '||':
112
+ tokens.push({ type: 'OPERATOR', value: chunk2 });
113
+ i += 2;
114
+ continue;
115
+ default:
116
+ }
117
+ // 1桁定義
118
+ const chunk1 = char;
119
+ switch (chunk1) {
120
+ case '>':
121
+ case '<':
122
+ case '!':
123
+ case '=':
124
+ tokens.push({ type: 'OPERATOR', value: chunk1 });
125
+ i += 1;
126
+ continue;
127
+ // case '.':
128
+ // tokens.push({ type: 'IDENTIFIER', value: chunk1 }); // '.'も識別子の一部として扱う
129
+ // i += 1;
130
+ // continue;
131
+ case '(':
132
+ case ')':
133
+ tokens.push({ type: 'PARENTHESIS', value: chunk1 });
134
+ i += 1;
135
+ continue;
136
+ default:
137
+ }
138
+ const reststring = condition.substring(i); // 現在のインデックスから末尾までの文字列
139
+ // 数値リテラル
140
+ const numMatch = reststring.match(/^-?\d+(\.\d+)?/);
141
+ if (numMatch) {
142
+ tokens.push({ type: 'NUMBER', value: parseFloat(numMatch[0]) });
143
+ i += numMatch[0].length;
144
+ continue;
145
+ }
146
+ // 文字列リテラル
147
+ switch (chunk1) {
148
+ case '\'':
149
+ case '"':
150
+ const quote = chunk1;
151
+ let j = i + 1;
152
+ let strValue = '';
153
+ while (j < condition.length && condition[j] !== quote) {
154
+ // エスケープ文字の処理 (\' や \\) は必要に応じて追加
155
+ if (condition[j] === '\\' && j + 1 < condition.length) {
156
+ strValue += condition[j + 1];
157
+ j += 2;
158
+ }
159
+ else {
160
+ strValue += condition[j];
161
+ j++;
162
+ }
163
+ }
164
+ if (condition[j] === quote) {
165
+ tokens.push({ type: 'STRING', value: strValue });
166
+ i = j + 1;
167
+ continue;
168
+ }
169
+ else {
170
+ // クォートが閉じられていない
171
+ throw new Error('Unterminated string literal');
172
+ }
173
+ default:
174
+ }
175
+ // 識別子 (変数名, true, false, null, undefined, length)
176
+ const identMatch = reststring.match(/^[a-zA-Z_][a-zA-Z0-9_.]*/); // ドットを含む識別子
177
+ if (identMatch) {
178
+ const ident = identMatch[0];
179
+ switch (ident) {
180
+ case 'true':
181
+ tokens.push({ type: 'BOOLEAN', value: true });
182
+ break;
183
+ case 'false':
184
+ tokens.push({ type: 'BOOLEAN', value: false });
185
+ break;
186
+ case 'null':
187
+ tokens.push({ type: 'NULL', value: null });
188
+ break;
189
+ case 'undefined':
190
+ tokens.push({ type: 'UNDEFINED', value: undefined });
191
+ break;
192
+ default:
193
+ tokens.push({ type: 'IDENTIFIER', value: ident }); // プロパティ名
194
+ }
195
+ i += ident.length;
196
+ continue;
197
+ }
198
+ // 未知の文字
199
+ throw new Error(`Unexpected character in condition: ${char} at index ${i}`);
200
+ }
201
+ return tokens;
202
+ }
203
+ /**
204
+ * Shunting Yardアルゴリズムで構文を逆ポーランド記法(Reverse Polish Notation)に変換する
205
+ *
206
+ * @param {Token[]} tokens
207
+ * @returns {Token[]}
208
+ */
209
+ shuntingYard(tokens) {
210
+ const output = [];
211
+ const operatorStack = [];
212
+ for (const token of tokens) {
213
+ switch (token.type) {
214
+ case 'NUMBER':
215
+ case 'BOOLEAN':
216
+ case 'NULL':
217
+ case 'UNDEFINED':
218
+ case 'STRING':
219
+ case 'IDENTIFIER':
220
+ output.push(token);
221
+ break;
222
+ case 'OPERATOR':
223
+ const op1 = token;
224
+ while (operatorStack.length) {
225
+ const op2 = operatorStack[operatorStack.length - 1];
226
+ // 括弧内は処理しない
227
+ if (op2.value === '(') {
228
+ break;
229
+ }
230
+ // 優先順位のルールに従う
231
+ if (PRECEDENCE[op1.value].associativity === 'left'
232
+ && PRECEDENCE[op1.value].precedence <= PRECEDENCE[op2.value].precedence) {
233
+ output.push(operatorStack.pop());
234
+ }
235
+ else {
236
+ break;
237
+ }
238
+ }
239
+ operatorStack.push(op1);
240
+ break;
241
+ case 'PARENTHESIS':
242
+ if (token.value === '(') {
243
+ operatorStack.push(token);
244
+ }
245
+ else if (token.value === ')') {
246
+ let foundLeftParen = false;
247
+ while (operatorStack.length > 0) {
248
+ const op = operatorStack.pop();
249
+ if ('value' in op && op.value === '(') {
250
+ foundLeftParen = true;
251
+ break;
252
+ }
253
+ output.push(op);
254
+ }
255
+ if (!foundLeftParen) {
256
+ throw new Error('Mismatched parentheses');
257
+ }
258
+ }
259
+ break;
260
+ // default:
261
+ }
262
+ }
263
+ while (operatorStack.length) {
264
+ const op = operatorStack.pop();
265
+ if ('value' in op && (op.value === '(' || op.value === ')')) {
266
+ throw new Error('Mismatched parentheses');
267
+ }
268
+ output.push(op);
269
+ }
270
+ return output;
271
+ }
272
+ /**
273
+ * 逆ポーランド記法(Reverse Polish Notation)のトークンを評価する
274
+ *
275
+ * @param {Token[]} rpnTokens
276
+ * @param {Record<string, any>} entity
277
+ * @returns {boolean}
278
+ */
279
+ evaluateRpn(rpnTokens, entity) {
280
+ const stack = [];
281
+ for (const token of rpnTokens) {
282
+ switch (token.type) {
283
+ case 'NUMBER':
284
+ case 'BOOLEAN':
285
+ case 'STRING':
286
+ case 'NULL':
287
+ case 'UNDEFINED':
288
+ stack.push(token.value);
289
+ break;
290
+ case 'IDENTIFIER':
291
+ stack.push(common.getProperty(entity, token.value));
292
+ break;
293
+ case 'OPERATOR':
294
+ // 単項演算子 '!'
295
+ if (token.value === '!') {
296
+ const operand = stack.pop();
297
+ stack.push(!operand);
298
+ break;
299
+ }
300
+ // 二項演算子
301
+ const right = stack.pop();
302
+ const left = stack.pop();
303
+ switch (token.value) {
304
+ case '==':
305
+ stack.push(left == right);
306
+ break;
307
+ case '!=':
308
+ stack.push(left != right);
309
+ break;
310
+ case '===':
311
+ stack.push(left === right);
312
+ break;
313
+ case '!==':
314
+ stack.push(left !== right);
315
+ break;
316
+ case '<':
317
+ stack.push(left < right);
318
+ break;
319
+ case '<=':
320
+ stack.push(left <= right);
321
+ break;
322
+ case '>':
323
+ stack.push(left > right);
324
+ break;
325
+ case '>=':
326
+ stack.push(left >= right);
327
+ break;
328
+ case '&&':
329
+ stack.push(left && right);
330
+ break;
331
+ case '||':
332
+ stack.push(left || right);
333
+ break;
334
+ default: throw new Error(`Unknown operator: ${token.value}`);
335
+ }
336
+ break;
337
+ // default:
338
+ }
339
+ }
340
+ if (stack.length !== 1) {
341
+ throw new Error('Invalid expression');
342
+ }
343
+ return !!stack[0];
344
+ }
345
+ }
346
+ exports.AbstractSyntaxTree = AbstractSyntaxTree;
347
+ //# sourceMappingURL=abstract-syntax-tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abstract-syntax-tree.js","sourceRoot":"","sources":["../src/abstract-syntax-tree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * entityで指定したオブジェクトからドットで連結されたプロパティキーに該当する値を取得する
3
+ *
4
+ * @param {Record<string, any>} entity
5
+ * @param {string} property
6
+ * @returns {any}
7
+ */
8
+ export declare function getProperty(entity: Record<string, any>, property: string): any;
package/lib/common.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getProperty = getProperty;
4
+ /**
5
+ * entityで指定したオブジェクトからドットで連結されたプロパティキーに該当する値を取得する
6
+ *
7
+ * @param {Record<string, any>} entity
8
+ * @param {string} property
9
+ * @returns {any}
10
+ */
11
+ function getProperty(entity, property) {
12
+ const propertyPath = property.split('.');
13
+ let value = entity;
14
+ for (const prop of propertyPath) {
15
+ if (value && value.hasOwnProperty(prop)) {
16
+ value = value[prop];
17
+ }
18
+ else {
19
+ return undefined;
20
+ }
21
+ }
22
+ return value;
23
+ }
24
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":";;AAOA,kCAWC;AAlBD;;;;;;GAMG;AACH,SAAgB,WAAW,CAAC,MAA2B,EAAE,QAAgB;IACvE,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,KAAK,GAAG,MAAM,CAAC;IACnB,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,IAAI,KAAK,IAAI,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1,3 +1,17 @@
1
+ /**
2
+ * PostgreSQL: $1, $2... 配列
3
+ * MySQL: ? 配列
4
+ * SQLite: ?, $name, :name 配列またはオブジェクト
5
+ * SQL Server: ?, `@name` 配列またはオブジェクト
6
+ * Oracle: :name オブジェクト
7
+ *
8
+ * 以下をサポートする
9
+ * ・$1, $2 (postgres)
10
+ * ・? (mysql) SQLite, SQL Serverもこれで代替可能
11
+ * ・:name (oracle) SQLiteもこれで代替可能
12
+ */
13
+ type BindType = 'postgres' | 'mysql' | 'oracle';
14
+ type BindParameterType<T extends 'postgres' | 'mysql' | 'oracle'> = T extends 'postgres' ? any[] : T extends 'mysql' ? any[] : Record<string, any>;
1
15
  /**
2
16
  * 動的SQLを生成する
3
17
  *
@@ -49,6 +63,16 @@ export declare class SQLBuilder {
49
63
  * @returns {string}
50
64
  */
51
65
  generateSQL(template: string, entity: Record<string, any>): string;
66
+ /**
67
+ * 指定したテンプレートにエンティティの値をバインド可能なプレースホルダー付きSQLを生成し、
68
+ * バインドパラメータと共にタプル型で返却する
69
+ *
70
+ * @param {string} template
71
+ * @param {Record<string, any>} entity
72
+ * @param {BindType} bindType
73
+ * @returns {[string, BindParameterType<T>]}
74
+ */
75
+ generateParameterizedSQL<T extends BindType>(template: string, entity: Record<string, any>, bindType: T): [string, BindParameterType<T>];
52
76
  /**
53
77
  * テンプレートに含まれるタグ構成を解析してコンテキストを返す
54
78
  *
@@ -63,6 +87,10 @@ export declare class SQLBuilder {
63
87
  * @param {string} template
64
88
  * @param {Record<string, any>} entity
65
89
  * @param {TagContext[]} tagContexts
90
+ * @param {*} [options]
91
+ * ├ bindType BindType
92
+ * ├ bindIndex number
93
+ * ├ bindParams BindParameterType<T>
66
94
  * @returns {string}
67
95
  */
68
96
  private parse;
@@ -84,6 +112,7 @@ export declare class SQLBuilder {
84
112
  private evaluateCondition;
85
113
  /**
86
114
  * entityからparamで指定した値を文字列で取得する
115
+ * entityの値がstringの場合、SQLインジェクションの危険のある文字はエスケープする
87
116
  *
88
117
  * * 返却する値が配列の場合は丸括弧で括り、各項目をカンマで区切る
89
118
  * ('a', 'b', 'c')
@@ -100,4 +129,14 @@ export declare class SQLBuilder {
100
129
  * @returns {string}
101
130
  */
102
131
  private extractValue;
132
+ /**
133
+ * SQLインジェクション対策
134
+ * * シングルクォートのエスケープ
135
+ * * バックスラッシュのエスケープ
136
+ *
137
+ * @param {string} str
138
+ * @returns {string}
139
+ */
140
+ private escape;
103
141
  }
142
+ export {};