pg-mvc-service 2.0.3 → 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.
- package/dist/clients/Base64Client.js +58 -0
- package/dist/models/SqlUtils/ValidateValueUtil.js +46 -0
- package/dist/models/SqlUtils/WhereExpression.js +163 -32
- package/dist/reqestResponse/ReqResType.js +0 -49
- package/dist/reqestResponse/RequestType.js +4 -3
- package/dist/reqestResponse/ResponseType.js +4 -3
- package/index.d.ts +0 -1
- package/package.json +3 -2
- package/src/clients/Base64Client.ts +68 -0
- package/src/models/SqlUtils/ValidateValueUtil.ts +52 -0
- package/src/models/SqlUtils/WhereExpression.ts +165 -33
- package/src/models/Type.ts +1 -1
- package/src/reqestResponse/ReqResType.ts +0 -56
- package/src/reqestResponse/RequestType.ts +4 -3
- package/src/reqestResponse/ResponseType.ts +4 -3
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.Base64Client = void 0;
|
|
16
16
|
const pdf_lib_1 = require("pdf-lib");
|
|
17
17
|
const sharp_1 = __importDefault(require("sharp"));
|
|
18
|
+
const type_utils_n_daira_1 = require("type-utils-n-daira");
|
|
18
19
|
class Base64Client {
|
|
19
20
|
constructor() { }
|
|
20
21
|
// public encode(text: string): string {
|
|
@@ -150,5 +151,62 @@ class Base64Client {
|
|
|
150
151
|
return Buffer.from(pdfBytes);
|
|
151
152
|
});
|
|
152
153
|
}
|
|
154
|
+
static isJpeg(value) {
|
|
155
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isBase64(value) === false) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
if (value.startsWith('data:')) {
|
|
159
|
+
if (value.startsWith('data:image/jpeg,') === false && value.startsWith('data:image/jpg,') === false) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
const valueParts = value.split(',');
|
|
163
|
+
if (valueParts.length !== 2) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
return valueParts[1].startsWith(this.PREFIX_JPEG_DATA);
|
|
167
|
+
}
|
|
168
|
+
return value.startsWith(this.PREFIX_JPEG_DATA);
|
|
169
|
+
}
|
|
170
|
+
static isPng(value) {
|
|
171
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isBase64(value) === false) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
if (value.startsWith('data:')) {
|
|
175
|
+
if (value.startsWith('data:image/png,') === false) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
const valueParts = value.split(',');
|
|
179
|
+
if (valueParts.length !== 2) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
return valueParts[1].startsWith(this.PREFIX_PNG_DATA);
|
|
183
|
+
}
|
|
184
|
+
return value.startsWith(this.PREFIX_PNG_DATA);
|
|
185
|
+
}
|
|
186
|
+
static tryConvertToPng(base64Value) {
|
|
187
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
188
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isBase64(base64Value) === false) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
const base64Data = base64Value.startsWith('data:') ? base64Value.split(',')[1] : base64Value;
|
|
192
|
+
if (this.isPng(base64Data)) {
|
|
193
|
+
return base64Data;
|
|
194
|
+
}
|
|
195
|
+
else if (this.isJpeg(base64Data)) {
|
|
196
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
197
|
+
try {
|
|
198
|
+
const pngBuffer = yield (0, sharp_1.default)(buffer)
|
|
199
|
+
.ensureAlpha().png().toBuffer();
|
|
200
|
+
return pngBuffer.toString('base64');
|
|
201
|
+
}
|
|
202
|
+
catch (e) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
153
209
|
}
|
|
154
210
|
exports.Base64Client = Base64Client;
|
|
211
|
+
Base64Client.PREFIX_JPEG_DATA = '/9j/';
|
|
212
|
+
Base64Client.PREFIX_PNG_DATA = 'iVBORw0KGgo';
|
|
@@ -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
|
-
|
|
128
|
-
|
|
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(`
|
|
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
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
|
@@ -114,55 +114,6 @@ class ReqResType {
|
|
|
114
114
|
return false;
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
-
/**
|
|
118
|
-
* 値がメールアドレス形式であるかどうかを検証します
|
|
119
|
-
* Validates if the given value is in the format of an email address
|
|
120
|
-
* @param value - 検証する値, The value to be validated
|
|
121
|
-
* @returns {boolean} - 値がメールアドレス形式であるかどうか, Whether the value is in the format of an email address
|
|
122
|
-
*/
|
|
123
|
-
isMail(value) {
|
|
124
|
-
if (typeof value !== 'string') {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
const pattern = new RegExp('^[a-zA-Z0-9_%+-]+([.][a-zA-Z0-9_%+-]+)*@[a-zA-Z0-9]+([-.]?[a-zA-Z0-9]+)*\\.[a-zA-Z]{2,}$');
|
|
128
|
-
return pattern.test(value);
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* 値がHTTPS URLであるかどうかを検証します
|
|
132
|
-
* Validates if the given value is an HTTPS URL
|
|
133
|
-
* @param value - 検証する値, The value to be validated
|
|
134
|
-
* @returns {boolean} - 値がHTTPS URLであるかどうか, Whether the value is an HTTPS URL
|
|
135
|
-
*/
|
|
136
|
-
isHttps(value) {
|
|
137
|
-
if (typeof value !== 'string') {
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
const urlPattern = new RegExp('^(https?:\\/\\/[^\\s/$.?#].[^\\s]*)$');
|
|
141
|
-
return urlPattern.test(value);
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* 値がBase64形式であるかどうかを検証します
|
|
145
|
-
* Validates if the given value is in Base64 format
|
|
146
|
-
* @param value - 検証する値, The value to be validated
|
|
147
|
-
* @returns {boolean} - 値がBase64形式であるかどうか, Whether the value is in Base64 format
|
|
148
|
-
*/
|
|
149
|
-
isBase64(value) {
|
|
150
|
-
if (typeof value !== 'string') {
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
// base64は4倍の長さである必要がある
|
|
154
|
-
if (value.length % 4 !== 0) {
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
// 基本的なbase64パターン
|
|
158
|
-
// 使用可能な文字
|
|
159
|
-
// ・ アルファベット(A-Z, a-z)
|
|
160
|
-
// ・ 数字(0-9)
|
|
161
|
-
// ・ +と/(基本文字)
|
|
162
|
-
// ・ =(パディング文字)
|
|
163
|
-
const base64Pattern = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
164
|
-
return base64Pattern.test(value);
|
|
165
|
-
}
|
|
166
117
|
/**
|
|
167
118
|
* プロパティの型をSwagger形式に変換します
|
|
168
119
|
* Converts the property type to Swagger format
|
|
@@ -7,6 +7,7 @@ exports.RequestType = void 0;
|
|
|
7
7
|
const ReqResType_1 = __importDefault(require("./ReqResType"));
|
|
8
8
|
const Exception_1 = require("../exceptions/Exception");
|
|
9
9
|
const StringUtil_1 = __importDefault(require("../Utils/StringUtil"));
|
|
10
|
+
const type_utils_n_daira_1 = require("type-utils-n-daira");
|
|
10
11
|
class RequestType extends ReqResType_1.default {
|
|
11
12
|
constructor() {
|
|
12
13
|
super(...arguments);
|
|
@@ -532,7 +533,7 @@ class RequestType extends ReqResType_1.default {
|
|
|
532
533
|
this.throwInputError(isRequestBody ? "UUID_21" : "UUID_91", keys, value);
|
|
533
534
|
case 'mail':
|
|
534
535
|
case 'mail?':
|
|
535
|
-
if (
|
|
536
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isMail(value)) {
|
|
536
537
|
return value;
|
|
537
538
|
}
|
|
538
539
|
this.throwInputError(isRequestBody ? "MAIL_21" : "MAIL_91", keys, value);
|
|
@@ -565,13 +566,13 @@ class RequestType extends ReqResType_1.default {
|
|
|
565
566
|
return value.replace('T', ' ');
|
|
566
567
|
case 'https':
|
|
567
568
|
case 'https?':
|
|
568
|
-
if (
|
|
569
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isHttps(value)) {
|
|
569
570
|
return value;
|
|
570
571
|
}
|
|
571
572
|
this.throwInputError(isRequestBody ? "HTTPS_21" : "HTTPS_91", keys, value);
|
|
572
573
|
case 'base64':
|
|
573
574
|
case 'base64?':
|
|
574
|
-
if (
|
|
575
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isBase64(value)) {
|
|
575
576
|
return value;
|
|
576
577
|
}
|
|
577
578
|
this.throwInputError(isRequestBody ? "BASE64_21" : "BASE64_91", keys, value);
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ResponseType = void 0;
|
|
7
|
+
const type_utils_n_daira_1 = require("type-utils-n-daira");
|
|
7
8
|
const StringUtil_1 = __importDefault(require("../Utils/StringUtil"));
|
|
8
9
|
const ReqResType_1 = __importDefault(require("./ReqResType"));
|
|
9
10
|
class ResponseType extends ReqResType_1.default {
|
|
@@ -210,7 +211,7 @@ class ResponseType extends ReqResType_1.default {
|
|
|
210
211
|
return undefined;
|
|
211
212
|
case 'mail':
|
|
212
213
|
case 'mail?':
|
|
213
|
-
if (
|
|
214
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isMail(value)) {
|
|
214
215
|
return value;
|
|
215
216
|
}
|
|
216
217
|
return undefined;
|
|
@@ -252,13 +253,13 @@ class ResponseType extends ReqResType_1.default {
|
|
|
252
253
|
return undefined;
|
|
253
254
|
case 'https':
|
|
254
255
|
case 'https?':
|
|
255
|
-
if (
|
|
256
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isHttps(value)) {
|
|
256
257
|
return value;
|
|
257
258
|
}
|
|
258
259
|
return undefined;
|
|
259
260
|
case 'base64':
|
|
260
261
|
case 'base64?':
|
|
261
|
-
if (
|
|
262
|
+
if (type_utils_n_daira_1.ValidateStringUtil.isBase64(value)) {
|
|
262
263
|
return value;
|
|
263
264
|
}
|
|
264
265
|
return undefined;
|
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.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "https://github.com/n-daira/npm-pack_mvc-service#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"axios": "1.10.0",
|
|
32
32
|
"crypto": "1.0.1",
|
|
33
33
|
"pdf-lib": "1.17.1",
|
|
34
|
-
"sharp": "0.34.1"
|
|
34
|
+
"sharp": "0.34.1",
|
|
35
|
+
"type-utils-n-daira": "1.0.11"
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PDFDocument } from 'pdf-lib';
|
|
2
2
|
import sharp from 'sharp';
|
|
3
|
+
import { ValidateStringUtil } from 'type-utils-n-daira';
|
|
3
4
|
|
|
4
5
|
export type TPng = 'image/png';
|
|
5
6
|
export type TJpeg = 'image/jpeg';
|
|
@@ -10,6 +11,9 @@ export type TPdf = 'application/pdf';
|
|
|
10
11
|
export type TJson = 'application/json';
|
|
11
12
|
|
|
12
13
|
export class Base64Client {
|
|
14
|
+
public static readonly PREFIX_JPEG_DATA = '/9j/';
|
|
15
|
+
public static readonly PREFIX_PNG_DATA = 'iVBORw0KGgo';
|
|
16
|
+
|
|
13
17
|
constructor() { }
|
|
14
18
|
|
|
15
19
|
// public encode(text: string): string {
|
|
@@ -152,4 +156,68 @@ export class Base64Client {
|
|
|
152
156
|
const pdfBytes = await pdfDoc.save();
|
|
153
157
|
return Buffer.from(pdfBytes);
|
|
154
158
|
}
|
|
159
|
+
|
|
160
|
+
public static isJpeg(value: any): value is string {
|
|
161
|
+
if (ValidateStringUtil.isBase64(value) === false) {
|
|
162
|
+
return false
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (value.startsWith('data:')) {
|
|
166
|
+
if (value.startsWith('data:image/jpeg,') === false && value.startsWith('data:image/jpg,') === false) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const valueParts = value.split(',');
|
|
171
|
+
if (valueParts.length !== 2) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return valueParts[1].startsWith(this.PREFIX_JPEG_DATA);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return value.startsWith(this.PREFIX_JPEG_DATA);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public static isPng(value: any): value is string {
|
|
182
|
+
if (ValidateStringUtil.isBase64(value) === false) {
|
|
183
|
+
return false
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (value.startsWith('data:')) {
|
|
187
|
+
if (value.startsWith('data:image/png,') === false) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const valueParts = value.split(',');
|
|
192
|
+
if (valueParts.length !== 2) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return valueParts[1].startsWith(this.PREFIX_PNG_DATA);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return value.startsWith(this.PREFIX_PNG_DATA);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
public static async tryConvertToPng(base64Value: any): Promise<string | false> {
|
|
203
|
+
if (ValidateStringUtil.isBase64(base64Value) === false) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const base64Data = base64Value.startsWith('data:') ? base64Value.split(',')[1] : base64Value;
|
|
208
|
+
if (this.isPng(base64Data)) {
|
|
209
|
+
return base64Data;
|
|
210
|
+
} else if (this.isJpeg(base64Data)) {
|
|
211
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
212
|
+
try {
|
|
213
|
+
const pngBuffer = await sharp(buffer)
|
|
214
|
+
.ensureAlpha().png().toBuffer();
|
|
215
|
+
return pngBuffer.toString('base64');
|
|
216
|
+
} catch (e) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
155
223
|
}
|
|
@@ -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]:
|
|
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
|
-
|
|
145
|
-
|
|
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(`
|
|
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
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
|
package/src/models/Type.ts
CHANGED
|
@@ -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 }
|
|
@@ -151,62 +151,6 @@ export default class ReqResType {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
/**
|
|
155
|
-
* 値がメールアドレス形式であるかどうかを検証します
|
|
156
|
-
* Validates if the given value is in the format of an email address
|
|
157
|
-
* @param value - 検証する値, The value to be validated
|
|
158
|
-
* @returns {boolean} - 値がメールアドレス形式であるかどうか, Whether the value is in the format of an email address
|
|
159
|
-
*/
|
|
160
|
-
protected isMail(value: any) {
|
|
161
|
-
if (typeof value !== 'string') {
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const pattern = new RegExp('^[a-zA-Z0-9_%+-]+([.][a-zA-Z0-9_%+-]+)*@[a-zA-Z0-9]+([-.]?[a-zA-Z0-9]+)*\\.[a-zA-Z]{2,}$');
|
|
166
|
-
return pattern.test(value);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* 値がHTTPS URLであるかどうかを検証します
|
|
171
|
-
* Validates if the given value is an HTTPS URL
|
|
172
|
-
* @param value - 検証する値, The value to be validated
|
|
173
|
-
* @returns {boolean} - 値がHTTPS URLであるかどうか, Whether the value is an HTTPS URL
|
|
174
|
-
*/
|
|
175
|
-
protected isHttps(value: any) {
|
|
176
|
-
if (typeof value !== 'string') {
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const urlPattern = new RegExp('^(https?:\\/\\/[^\\s/$.?#].[^\\s]*)$');
|
|
181
|
-
return urlPattern.test(value);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* 値がBase64形式であるかどうかを検証します
|
|
186
|
-
* Validates if the given value is in Base64 format
|
|
187
|
-
* @param value - 検証する値, The value to be validated
|
|
188
|
-
* @returns {boolean} - 値がBase64形式であるかどうか, Whether the value is in Base64 format
|
|
189
|
-
*/
|
|
190
|
-
protected isBase64(value: any) {
|
|
191
|
-
if (typeof value !== 'string') {
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// base64は4倍の長さである必要がある
|
|
196
|
-
if (value.length % 4 !== 0) {
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// 基本的なbase64パターン
|
|
201
|
-
// 使用可能な文字
|
|
202
|
-
// ・ アルファベット(A-Z, a-z)
|
|
203
|
-
// ・ 数字(0-9)
|
|
204
|
-
// ・ +と/(基本文字)
|
|
205
|
-
// ・ =(パディング文字)
|
|
206
|
-
const base64Pattern = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
207
|
-
return base64Pattern.test(value);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
154
|
/**
|
|
211
155
|
* プロパティの型をSwagger形式に変換します
|
|
212
156
|
* Converts the property type to Swagger format
|
|
@@ -2,6 +2,7 @@ import { Request } from 'express';
|
|
|
2
2
|
import ReqResType, { EnumType, PrimitiveType, PropertyType } from "./ReqResType";
|
|
3
3
|
import { InputErrorException } from '../exceptions/Exception';
|
|
4
4
|
import StringUtil from '../Utils/StringUtil';
|
|
5
|
+
import { ValidateStringUtil } from 'type-utils-n-daira';
|
|
5
6
|
|
|
6
7
|
// エラーメッセージの型定義
|
|
7
8
|
export interface ErrorMessageType {
|
|
@@ -575,7 +576,7 @@ export class RequestType extends ReqResType {
|
|
|
575
576
|
this.throwInputError(isRequestBody ? "UUID_21" : "UUID_91", keys, value);
|
|
576
577
|
case 'mail':
|
|
577
578
|
case 'mail?':
|
|
578
|
-
if (
|
|
579
|
+
if (ValidateStringUtil.isMail(value)) {
|
|
579
580
|
return value;
|
|
580
581
|
}
|
|
581
582
|
this.throwInputError(isRequestBody ? "MAIL_21" : "MAIL_91", keys, value);
|
|
@@ -611,13 +612,13 @@ export class RequestType extends ReqResType {
|
|
|
611
612
|
return value.replace('T', ' ');
|
|
612
613
|
case 'https':
|
|
613
614
|
case 'https?':
|
|
614
|
-
if (
|
|
615
|
+
if (ValidateStringUtil.isHttps(value)) {
|
|
615
616
|
return value;
|
|
616
617
|
}
|
|
617
618
|
this.throwInputError(isRequestBody ? "HTTPS_21" : "HTTPS_91", keys, value);
|
|
618
619
|
case 'base64':
|
|
619
620
|
case 'base64?':
|
|
620
|
-
if (
|
|
621
|
+
if (ValidateStringUtil.isBase64(value)) {
|
|
621
622
|
return value;
|
|
622
623
|
}
|
|
623
624
|
this.throwInputError(isRequestBody ? "BASE64_21" : "BASE64_91", keys, value);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ValidateStringUtil } from "type-utils-n-daira";
|
|
1
2
|
import StringUtil from "../Utils/StringUtil";
|
|
2
3
|
import ReqResType from "./ReqResType";
|
|
3
4
|
|
|
@@ -226,7 +227,7 @@ export class ResponseType extends ReqResType {
|
|
|
226
227
|
return undefined;
|
|
227
228
|
case 'mail':
|
|
228
229
|
case 'mail?':
|
|
229
|
-
if (
|
|
230
|
+
if (ValidateStringUtil.isMail(value)) {
|
|
230
231
|
return value;
|
|
231
232
|
}
|
|
232
233
|
return undefined;
|
|
@@ -274,13 +275,13 @@ export class ResponseType extends ReqResType {
|
|
|
274
275
|
return undefined;
|
|
275
276
|
case 'https':
|
|
276
277
|
case 'https?':
|
|
277
|
-
if (
|
|
278
|
+
if (ValidateStringUtil.isHttps(value)) {
|
|
278
279
|
return value;
|
|
279
280
|
}
|
|
280
281
|
return undefined;
|
|
281
282
|
case 'base64':
|
|
282
283
|
case 'base64?':
|
|
283
|
-
if (
|
|
284
|
+
if (ValidateStringUtil.isBase64(value)) {
|
|
284
285
|
return value;
|
|
285
286
|
}
|
|
286
287
|
return undefined;
|