pg-mvc-service 2.0.4 → 2.0.5

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.
@@ -198,6 +198,52 @@ class ValidateValueUtil {
198
198
  }
199
199
  return true;
200
200
  }
201
+ static isErrorInteger(value) {
202
+ let numberValue;
203
+ if (typeof value === 'string') {
204
+ if (value.trim() === "" || isNaN(Number(value))) {
205
+ return true;
206
+ }
207
+ numberValue = Number(value);
208
+ }
209
+ else if (typeof value === 'number') {
210
+ numberValue = value;
211
+ }
212
+ else {
213
+ return true;
214
+ }
215
+ if (Number.isInteger(numberValue) === false) {
216
+ return true;
217
+ }
218
+ if (numberValue < -2147483648 || numberValue > 2147483647) {
219
+ return true;
220
+ }
221
+ return false;
222
+ }
223
+ static isErrorReal(value) {
224
+ let numberValue;
225
+ if (typeof value === 'string') {
226
+ if (value.trim() === "" || isNaN(Number(value))) {
227
+ return true;
228
+ }
229
+ numberValue = Number(value);
230
+ }
231
+ else if (typeof value === 'number') {
232
+ numberValue = value;
233
+ }
234
+ else {
235
+ return true;
236
+ }
237
+ // 特殊値チェック
238
+ if (isFinite(numberValue) === false) {
239
+ return true;
240
+ }
241
+ // 範囲チェック(real型の範囲)
242
+ if (numberValue < -3.4e38 || numberValue > 3.4e38) {
243
+ return true;
244
+ }
245
+ return false;
246
+ }
201
247
  static isErrorNumber(value) {
202
248
  if (typeof value === 'string') {
203
249
  if (value.trim() === "" || isNaN(Number(value))) {
@@ -83,21 +83,21 @@ class WhereExpression {
83
83
  // Are the operators correct?
84
84
  const useableOperator = {
85
85
  integer: ["=", "!=", ">", ">=", "<", "<=", "in", "not in"],
86
- 'integer[]': [],
86
+ 'integer[]': ["=", "any", "@>", "&&"],
87
87
  real: ["=", "!=", ">", ">=", "<", "<="],
88
- 'real[]': [],
88
+ 'real[]': ["=", "any", "@>", "&&"],
89
89
  string: ["=", "!=", "like", "ilike", "h2f_like", "h2f_ilike", "in", "not in"],
90
- 'string[]': [],
90
+ 'string[]': ["=", "any", "@>", "&&"],
91
91
  uuid: ["=", "!=", "in", "not in"],
92
- 'uuid[]': [],
92
+ 'uuid[]': ["=", "any", "@>", "&&"],
93
93
  bool: ["=", "!=", "in", "not in"],
94
- 'bool[]': [],
94
+ 'bool[]': ["=", "any", "@>", "&&"],
95
95
  date: ["=", "!=", ">", ">=", "<", "<="],
96
- 'date[]': [],
96
+ 'date[]': ["=", "any", "@>", "&&"],
97
97
  time: ["=", "!=", ">", ">=", "<", "<="],
98
- 'time[]': [],
98
+ 'time[]': ["=", "any", "@>", "&&"],
99
99
  timestamp: ["=", "!=", ">", ">=", "<", "<="],
100
- 'timestamp[]': [],
100
+ 'timestamp[]': ["=", "any", "@>", "&&"],
101
101
  json: [],
102
102
  'json[]': [],
103
103
  jsonb: [],
@@ -124,8 +124,15 @@ class WhereExpression {
124
124
  throw new Error(`When comparing with null, operators other than =, != cannot be used. (${operator})`);
125
125
  }
126
126
  }
127
- if (leftColumn.type.endsWith("[]")) {
128
- return this.createExpression(leftColumn, operator, right, varLength);
127
+ const isColumnRight = right !== null && typeof right === 'object' && 'model' in right && 'name' in right;
128
+ const isArrayColumnLeft = leftColumn.type.endsWith("[]");
129
+ if (isArrayColumnLeft) {
130
+ if (isColumnRight) {
131
+ return this.createExpressionArrayColumn(leftColumn, operator, right, varLength);
132
+ }
133
+ else {
134
+ return this.createExpressionArrayValue(leftColumn, operator, right, varLength);
135
+ }
129
136
  }
130
137
  else {
131
138
  return this.createExpression(leftColumn, operator, right, varLength);
@@ -156,8 +163,9 @@ class WhereExpression {
156
163
  // If the right side value is a column specification
157
164
  if (right !== null && typeof right === 'object' && 'model' in right && 'name' in right) {
158
165
  const rightColumn = right.model.getColumn(right.name);
166
+ // 型の不一致エラーメッセージを改善
159
167
  if (leftColumn.type !== rightColumn.type) {
160
- throw new Error(`The types of [${leftColumn.tableName}].[${leftColumn.columnName}] and [${rightColumn.tableName}].[${rightColumn.columnName}] are different.`);
168
+ throw new Error(`Type mismatch: column [${leftColumn.tableName}].[${leftColumn.columnName}] (${leftColumn.type}) and [${rightColumn.tableName}].[${rightColumn.columnName}] (${rightColumn.type}) must be the same type.`);
161
169
  }
162
170
  // LIKE operators are different, so handle separately
163
171
  switch (operator) {
@@ -198,34 +206,157 @@ class WhereExpression {
198
206
  };
199
207
  }
200
208
  static createExpressionArrayValue(leftColumn, operator, right, varLength) {
201
- // ValidateValueUtil.validateValue(leftColumn, right);
202
- // LIKE operators are different, so handle separately
203
- // switch (operator) {
204
- // case 'like':
205
- // case 'ilike':
206
- // return {
207
- // sql: `${leftColumn.expression} ${operator} $${varLength}`,
208
- // vars: [`%${right}%`]
209
- // }
210
- // case 'h2f_like': // half to full like
211
- // case 'h2f_ilike': // half to full ilike
212
- // return {
213
- // sql: `${this.makeSqlReplaceHalfToFull(leftColumn.expression)} ${operator.replace("h2f_", "")} ${this.makeSqlReplaceHalfToFull(`$${varLength}`)}`,
214
- // vars: [`%${right}%`]
215
- // }
216
- // }
209
+ // バリデーションチェック
210
+ switch (operator) {
211
+ case 'any':
212
+ switch (leftColumn.type) {
213
+ case 'integer[]':
214
+ if (ValidateValueUtil_1.default.isErrorInteger(right)) {
215
+ throw new Error(`Expected integer value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
216
+ }
217
+ break;
218
+ case 'real[]':
219
+ if (ValidateValueUtil_1.default.isErrorReal(right)) {
220
+ throw new Error(`Expected numeric value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
221
+ }
222
+ break;
223
+ case 'string[]':
224
+ if (ValidateValueUtil_1.default.isErrorString(right)) {
225
+ throw new Error(`Expected string value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
226
+ }
227
+ break;
228
+ case 'uuid[]':
229
+ if (ValidateValueUtil_1.default.isErrorUUID(right)) {
230
+ throw new Error(`Expected UUID value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
231
+ }
232
+ break;
233
+ case 'bool[]':
234
+ if (ValidateValueUtil_1.default.isErrorBool(right)) {
235
+ throw new Error(`Expected boolean value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
236
+ }
237
+ break;
238
+ case 'date[]':
239
+ if (ValidateValueUtil_1.default.isErrorDate(right)) {
240
+ throw new Error(`Expected date value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
241
+ }
242
+ break;
243
+ case 'time[]':
244
+ if (ValidateValueUtil_1.default.isErrorTime(right)) {
245
+ throw new Error(`Expected time value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
246
+ }
247
+ break;
248
+ case 'timestamp[]':
249
+ if (ValidateValueUtil_1.default.isErrorTimestamp(right)) {
250
+ throw new Error(`Expected timestamp value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
251
+ }
252
+ break;
253
+ }
254
+ break;
255
+ case '=':
256
+ case '@>':
257
+ case '&&':
258
+ if (Array.isArray(right) === false) {
259
+ throw new Error(`Expected array format for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
260
+ }
261
+ for (const value of right) {
262
+ switch (leftColumn.type) {
263
+ case 'integer[]':
264
+ if (ValidateValueUtil_1.default.isErrorInteger(value)) {
265
+ throw new Error(`Expected integer value in array element, but received: ${JSON.stringify(value)}`);
266
+ }
267
+ break;
268
+ case 'real[]':
269
+ if (ValidateValueUtil_1.default.isErrorReal(value)) {
270
+ throw new Error(`Expected numeric value in array element, but received: ${JSON.stringify(value)}`);
271
+ }
272
+ break;
273
+ case 'string[]':
274
+ if (ValidateValueUtil_1.default.isErrorString(value)) {
275
+ throw new Error(`Expected string value in array element, but received: ${JSON.stringify(value)}`);
276
+ }
277
+ break;
278
+ case 'uuid[]':
279
+ if (ValidateValueUtil_1.default.isErrorUUID(value)) {
280
+ throw new Error(`Expected UUID value in array element, but received: ${JSON.stringify(value)}`);
281
+ }
282
+ break;
283
+ case 'bool[]':
284
+ if (ValidateValueUtil_1.default.isErrorBool(value)) {
285
+ throw new Error(`Expected boolean value in array element, but received: ${JSON.stringify(value)}`);
286
+ }
287
+ break;
288
+ case 'date[]':
289
+ if (ValidateValueUtil_1.default.isErrorDate(value)) {
290
+ throw new Error(`Expected date value in array element, but received: ${JSON.stringify(value)}`);
291
+ }
292
+ break;
293
+ case 'time[]':
294
+ if (ValidateValueUtil_1.default.isErrorTime(value)) {
295
+ throw new Error(`Expected time value in array element, but received: ${JSON.stringify(value)}`);
296
+ }
297
+ break;
298
+ case 'timestamp[]':
299
+ if (ValidateValueUtil_1.default.isErrorTimestamp(value)) {
300
+ throw new Error(`Expected timestamp value in array element, but received: ${JSON.stringify(value)}`);
301
+ }
302
+ break;
303
+ }
304
+ }
305
+ break;
306
+ default:
307
+ throw new Error(`Unsupported operator '${operator}' for array column operations.`);
308
+ }
217
309
  switch (operator) {
218
310
  case '=':
219
- // バリデーションチェックをする
311
+ case '@>':
312
+ case '&&':
220
313
  return {
221
314
  expression: `${leftColumn.expression} ${operator} $${varLength}`,
222
315
  vars: [right]
223
316
  };
317
+ case 'any':
318
+ return {
319
+ expression: `$${varLength} = ANY(${leftColumn.expression})`,
320
+ vars: [right]
321
+ };
322
+ }
323
+ }
324
+ static createExpressionArrayColumn(leftColumn, operator, right, varLength) {
325
+ const rightColumn = right.model.getColumn(right.name);
326
+ // バリデーションチェック
327
+ switch (operator) {
328
+ case 'any':
329
+ // any演算子の場合
330
+ if (leftColumn.type !== rightColumn.type.replace('[]', '')) {
331
+ throw new Error(`Type mismatch: array column [${leftColumn.tableName}].[${leftColumn.columnName}] (${leftColumn.type}) and scalar column [${rightColumn.tableName}].[${rightColumn.columnName}] (${rightColumn.type}) are incompatible for ANY operation.`);
332
+ }
333
+ break;
334
+ case '=':
335
+ case '@>':
336
+ case '&&':
337
+ // 配列演算子の場合
338
+ if (leftColumn.type !== rightColumn.type) {
339
+ throw new Error(`Type mismatch: array columns [${leftColumn.tableName}].[${leftColumn.columnName}] (${leftColumn.type}) and [${rightColumn.tableName}].[${rightColumn.columnName}] (${rightColumn.type}) must be the same type.`);
340
+ }
341
+ break;
342
+ default:
343
+ // サポートされていない演算子
344
+ throw new Error(`Operator '${operator}' is not supported for array column operations. Supported operators: =, @>, &&, ANY`);
345
+ }
346
+ switch (operator) {
347
+ case '=':
348
+ case '@>':
349
+ case '&&':
350
+ return {
351
+ expression: `${leftColumn.expression} ${operator} $${rightColumn.expression}`,
352
+ vars: []
353
+ };
354
+ case 'any':
355
+ return {
356
+ expression: `$${rightColumn.expression} = ANY(${leftColumn.expression})`,
357
+ vars: []
358
+ };
224
359
  }
225
- return {
226
- expression: `${leftColumn.expression} ${operator} $${varLength}`,
227
- vars: [right]
228
- };
229
360
  }
230
361
  /**
231
362
  * SQL statement to convert half-width characters to full-width
package/index.d.ts CHANGED
@@ -20,7 +20,6 @@ import ValidateClient from './src/models/ValidateClient';
20
20
  import { TableModel } from "./src/models/TableModel";
21
21
  export { TableModel } from "./src/models/TableModel";
22
22
 
23
- import { TColumnAttribute, TColumnType, TColumnArrayType, TColumn, TColumnDetail, TOperator, TColumnInfo, TQuery, TSelectExpression, TAggregateFuncType, TCondition, TNestedCondition, TSortKeyword, TKeyFormat } from './src/models/Type';
24
23
  export { TColumnAttribute, TColumnType, TColumnArrayType, TColumn, TColumnDetail, TOperator, TColumnInfo, TQuery, TSelectExpression, TAggregateFuncType, TCondition, TNestedCondition, TSortKeyword, TKeyFormat } from './src/models/Type';
25
24
 
26
25
  declare module 'pg-mvc-service' {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pg-mvc-service",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "",
5
5
  "homepage": "https://github.com/n-daira/npm-pack_mvc-service#readme",
6
6
  "bugs": {
@@ -216,6 +216,58 @@ export default class ValidateValueUtil {
216
216
  return true;
217
217
  }
218
218
 
219
+ static isErrorInteger(value: any): boolean {
220
+ let numberValue: number;
221
+ if (typeof value === 'string') {
222
+ if (value.trim() === "" || isNaN(Number(value))) {
223
+ return true;
224
+ }
225
+
226
+ numberValue = Number(value);
227
+ } else if (typeof value === 'number') {
228
+ numberValue = value;
229
+ } else {
230
+ return true;
231
+ }
232
+
233
+ if (Number.isInteger(numberValue) === false) {
234
+ return true;
235
+ }
236
+
237
+ if (numberValue < -2147483648 || numberValue > 2147483647) {
238
+ return true;
239
+ }
240
+
241
+ return false;
242
+ }
243
+
244
+ static isErrorReal(value: any): boolean {
245
+ let numberValue: number;
246
+ if (typeof value === 'string') {
247
+ if (value.trim() === "" || isNaN(Number(value))) {
248
+ return true;
249
+ }
250
+
251
+ numberValue = Number(value);
252
+ } else if (typeof value === 'number') {
253
+ numberValue = value;
254
+ } else {
255
+ return true;
256
+ }
257
+
258
+ // 特殊値チェック
259
+ if (isFinite(numberValue) === false) {
260
+ return true;
261
+ }
262
+
263
+ // 範囲チェック(real型の範囲)
264
+ if (numberValue < -3.4e38 || numberValue > 3.4e38) {
265
+ return true;
266
+ }
267
+
268
+ return false;
269
+ }
270
+
219
271
  static isErrorNumber(value: any): boolean {
220
272
  if (typeof value === 'string') {
221
273
  if (value.trim() === "" || isNaN(Number(value))) {
@@ -96,23 +96,23 @@ export default class WhereExpression {
96
96
  const leftColumn = left.model.getColumn(left.name);
97
97
 
98
98
  // Are the operators correct?
99
- const useableOperator: { [key in TColumnType | TColumnArrayType]: string[] } = {
99
+ const useableOperator: { [key in TColumnType | TColumnArrayType]: TOperator[] } = {
100
100
  integer: ["=", "!=", ">", ">=", "<", "<=", "in", "not in"],
101
- 'integer[]': [],
101
+ 'integer[]': ["=", "any", "@>", "&&"],
102
102
  real: ["=", "!=", ">", ">=", "<", "<="],
103
- 'real[]': [],
103
+ 'real[]': ["=", "any", "@>", "&&"],
104
104
  string: ["=", "!=", "like", "ilike", "h2f_like", "h2f_ilike", "in", "not in"],
105
- 'string[]': [],
105
+ 'string[]': ["=", "any", "@>", "&&"],
106
106
  uuid: ["=", "!=", "in", "not in"],
107
- 'uuid[]': [],
107
+ 'uuid[]': ["=", "any", "@>", "&&"],
108
108
  bool: ["=", "!=", "in", "not in"],
109
- 'bool[]': [],
109
+ 'bool[]': ["=", "any", "@>", "&&"],
110
110
  date: ["=", "!=", ">", ">=", "<", "<="],
111
- 'date[]': [],
111
+ 'date[]': ["=", "any", "@>", "&&"],
112
112
  time: ["=", "!=", ">", ">=", "<", "<="],
113
- 'time[]': [],
113
+ 'time[]': ["=", "any", "@>", "&&"],
114
114
  timestamp: ["=", "!=", ">", ">=", "<", "<="],
115
- 'timestamp[]': [],
115
+ 'timestamp[]': ["=", "any", "@>", "&&"],
116
116
  json: [],
117
117
  'json[]': [],
118
118
  jsonb: [],
@@ -141,8 +141,14 @@ export default class WhereExpression {
141
141
  }
142
142
  }
143
143
 
144
- if (leftColumn.type.endsWith("[]")) {
145
- return this.createExpression(leftColumn, operator, right, varLength);
144
+ const isColumnRight = right !== null && typeof right === 'object' && 'model' in right && 'name' in right;
145
+ const isArrayColumnLeft = leftColumn.type.endsWith("[]");
146
+ if (isArrayColumnLeft) {
147
+ if (isColumnRight) {
148
+ return this.createExpressionArrayColumn(leftColumn, operator, right, varLength);
149
+ } else {
150
+ return this.createExpressionArrayValue(leftColumn, operator, right, varLength);
151
+ }
146
152
  } else {
147
153
  return this.createExpression(leftColumn, operator, right, varLength);
148
154
  }
@@ -176,8 +182,9 @@ export default class WhereExpression {
176
182
  if (right !== null && typeof right === 'object' && 'model' in right && 'name' in right) {
177
183
  const rightColumn = right.model.getColumn(right.name);
178
184
 
185
+ // 型の不一致エラーメッセージを改善
179
186
  if (leftColumn.type !== rightColumn.type) {
180
- throw new Error(`The types of [${leftColumn.tableName}].[${leftColumn.columnName}] and [${rightColumn.tableName}].[${rightColumn.columnName}] are different.`);
187
+ throw new Error(`Type mismatch: column [${leftColumn.tableName}].[${leftColumn.columnName}] (${leftColumn.type}) and [${rightColumn.tableName}].[${rightColumn.columnName}] (${rightColumn.type}) must be the same type.`);
181
188
  }
182
189
 
183
190
  // LIKE operators are different, so handle separately
@@ -224,37 +231,162 @@ export default class WhereExpression {
224
231
 
225
232
  private static createExpressionArrayValue(leftColumn: TColumnDetail, operator: TOperator, right: any, varLength: number) : TQuery {
226
233
 
227
- // ValidateValueUtil.validateValue(leftColumn, right);
228
- // LIKE operators are different, so handle separately
229
- // switch (operator) {
230
- // case 'like':
231
- // case 'ilike':
232
- // return {
233
- // sql: `${leftColumn.expression} ${operator} $${varLength}`,
234
- // vars: [`%${right}%`]
235
- // }
236
- // case 'h2f_like': // half to full like
237
- // case 'h2f_ilike': // half to full ilike
238
- // return {
239
- // sql: `${this.makeSqlReplaceHalfToFull(leftColumn.expression)} ${operator.replace("h2f_", "")} ${this.makeSqlReplaceHalfToFull(`$${varLength}`)}`,
240
- // vars: [`%${right}%`]
241
- // }
242
- // }
234
+ // バリデーションチェック
235
+ switch (operator) {
236
+ case 'any':
237
+ switch (leftColumn.type) {
238
+ case 'integer[]':
239
+ if (ValidateValueUtil.isErrorInteger(right)) {
240
+ throw new Error(`Expected integer value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
241
+ }
242
+ break;
243
+ case 'real[]':
244
+ if (ValidateValueUtil.isErrorReal(right)) {
245
+ throw new Error(`Expected numeric value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
246
+ }
247
+ break;
248
+ case 'string[]':
249
+ if (ValidateValueUtil.isErrorString(right)) {
250
+ throw new Error(`Expected string value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
251
+ }
252
+ break;
253
+ case 'uuid[]':
254
+ if (ValidateValueUtil.isErrorUUID(right)) {
255
+ throw new Error(`Expected UUID value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
256
+ }
257
+ break;
258
+ case 'bool[]':
259
+ if (ValidateValueUtil.isErrorBool(right)) {
260
+ throw new Error(`Expected boolean value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
261
+ }
262
+ break;
263
+ case 'date[]':
264
+ if (ValidateValueUtil.isErrorDate(right)) {
265
+ throw new Error(`Expected date value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
266
+ }
267
+ break;
268
+ case 'time[]':
269
+ if (ValidateValueUtil.isErrorTime(right)) {
270
+ throw new Error(`Expected time value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
271
+ }
272
+ break;
273
+ case 'timestamp[]':
274
+ if (ValidateValueUtil.isErrorTimestamp(right)) {
275
+ throw new Error(`Expected timestamp value for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
276
+ }
277
+ break;
278
+ }
279
+ break;
280
+ case '=':
281
+ case '@>':
282
+ case '&&':
283
+ if (Array.isArray(right) === false) {
284
+ throw new Error(`Expected array format for array column (${leftColumn.type}), but received: ${JSON.stringify(right)}`);
285
+ }
286
+
287
+ for (const value of right) {
288
+ switch (leftColumn.type) {
289
+ case 'integer[]':
290
+ if (ValidateValueUtil.isErrorInteger(value)) {
291
+ throw new Error(`Expected integer value in array element, but received: ${JSON.stringify(value)}`);
292
+ }
293
+ break;
294
+ case 'real[]':
295
+ if (ValidateValueUtil.isErrorReal(value)) {
296
+ throw new Error(`Expected numeric value in array element, but received: ${JSON.stringify(value)}`);
297
+ }
298
+ break;
299
+ case 'string[]':
300
+ if (ValidateValueUtil.isErrorString(value)) {
301
+ throw new Error(`Expected string value in array element, but received: ${JSON.stringify(value)}`);
302
+ }
303
+ break;
304
+ case 'uuid[]':
305
+ if (ValidateValueUtil.isErrorUUID(value)) {
306
+ throw new Error(`Expected UUID value in array element, but received: ${JSON.stringify(value)}`);
307
+ }
308
+ break;
309
+ case 'bool[]':
310
+ if (ValidateValueUtil.isErrorBool(value)) {
311
+ throw new Error(`Expected boolean value in array element, but received: ${JSON.stringify(value)}`);
312
+ }
313
+ break;
314
+ case 'date[]':
315
+ if (ValidateValueUtil.isErrorDate(value)) {
316
+ throw new Error(`Expected date value in array element, but received: ${JSON.stringify(value)}`);
317
+ }
318
+ break;
319
+ case 'time[]':
320
+ if (ValidateValueUtil.isErrorTime(value)) {
321
+ throw new Error(`Expected time value in array element, but received: ${JSON.stringify(value)}`);
322
+ }
323
+ break;
324
+ case 'timestamp[]':
325
+ if (ValidateValueUtil.isErrorTimestamp(value)) {
326
+ throw new Error(`Expected timestamp value in array element, but received: ${JSON.stringify(value)}`);
327
+ }
328
+ break;
329
+ }
330
+ }
331
+ break;
332
+ default:
333
+ throw new Error(`Unsupported operator '${operator}' for array column operations.`);
334
+ }
243
335
 
244
336
  switch (operator) {
245
337
  case '=':
246
- // バリデーションチェックをする
247
-
338
+ case '@>':
339
+ case '&&':
248
340
  return {
249
341
  expression: `${leftColumn.expression} ${operator} $${varLength}`,
250
342
  vars: [right]
251
343
  }
344
+ case 'any':
345
+ return {
346
+ expression: `$${varLength} = ANY(${leftColumn.expression})`,
347
+ vars: [right]
348
+ }
252
349
  }
350
+ }
253
351
 
352
+ private static createExpressionArrayColumn(leftColumn: TColumnDetail, operator: TOperator, right: TColumnInfo, varLength: number) : TQuery {
254
353
 
255
- return {
256
- expression: `${leftColumn.expression} ${operator} $${varLength}`,
257
- vars: [right]
354
+ const rightColumn = right.model.getColumn(right.name);
355
+
356
+ // バリデーションチェック
357
+ switch (operator) {
358
+ case 'any':
359
+ // any演算子の場合
360
+ if (leftColumn.type !== rightColumn.type.replace('[]', '')) {
361
+ throw new Error(`Type mismatch: array column [${leftColumn.tableName}].[${leftColumn.columnName}] (${leftColumn.type}) and scalar column [${rightColumn.tableName}].[${rightColumn.columnName}] (${rightColumn.type}) are incompatible for ANY operation.`);
362
+ }
363
+ break;
364
+ case '=':
365
+ case '@>':
366
+ case '&&':
367
+ // 配列演算子の場合
368
+ if (leftColumn.type !== rightColumn.type) {
369
+ throw new Error(`Type mismatch: array columns [${leftColumn.tableName}].[${leftColumn.columnName}] (${leftColumn.type}) and [${rightColumn.tableName}].[${rightColumn.columnName}] (${rightColumn.type}) must be the same type.`);
370
+ }
371
+ break;
372
+ default:
373
+ // サポートされていない演算子
374
+ throw new Error(`Operator '${operator}' is not supported for array column operations. Supported operators: =, @>, &&, ANY`);
375
+ }
376
+
377
+ switch (operator) {
378
+ case '=':
379
+ case '@>':
380
+ case '&&':
381
+ return {
382
+ expression: `${leftColumn.expression} ${operator} $${rightColumn.expression}`,
383
+ vars: []
384
+ }
385
+ case 'any':
386
+ return {
387
+ expression: `$${rightColumn.expression} = ANY(${leftColumn.expression})`,
388
+ vars: []
389
+ }
258
390
  }
259
391
  }
260
392
 
@@ -47,7 +47,7 @@ export type TColumnDetail = TColumn & {
47
47
  expression: string
48
48
  }
49
49
 
50
- export type TOperator = "=" | "!=" | ">" | ">=" | "<" | "<=" | "like" | "ilike" | "h2f_like" | "h2f_ilike" | "in" | "not in";
50
+ export type TOperator = "=" | "!=" | ">" | ">=" | "<" | "<=" | "like" | "ilike" | "h2f_like" | "h2f_ilike" | "in" | "not in" | "any" | "@>" | "&&";
51
51
  export type TColumnInfo = { model: TableModel, name: string }
52
52
  export type TQuery = {expression: string, vars?: Array<any>};
53
53
  export type TSelectExpression = { expression: string, alias: string }