pg-mvc-service 1.0.16 → 1.0.18
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/models/SqlUtils/ValidateValueUtil.js +28 -0
- package/dist/models/SqlUtils/WhereExpression.js +5 -1
- package/dist/models/TableDoc.js +8 -2
- package/dist/models/TableModel.js +8 -0
- package/dist/models/ValidateClient.js +10 -10
- package/index.d.ts +18 -66
- package/package.json +1 -1
- package/src/Service.ts +1 -1
- package/src/models/SqlUtils/ValidateValueUtil.ts +30 -0
- package/src/models/SqlUtils/WhereExpression.ts +9 -5
- package/src/models/TableDoc.ts +6 -2
- package/src/models/TableModel.ts +20 -12
- package/src/models/Type.ts +15 -12
- package/src/models/ValidateClient.ts +10 -11
|
@@ -117,6 +117,12 @@ class ValidateValueUtil {
|
|
|
117
117
|
throw new Error('Please enter a value of type bool, or a string "true" or "false", or a number 0 or 1.');
|
|
118
118
|
}
|
|
119
119
|
break;
|
|
120
|
+
case "json":
|
|
121
|
+
case "jsonb":
|
|
122
|
+
if (this.isErrorJson(value)) {
|
|
123
|
+
throw new Error('Please enter a value as an Object or JSON string.');
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
static isErrorValue(columnType, value) {
|
|
@@ -149,6 +155,10 @@ class ValidateValueUtil {
|
|
|
149
155
|
case "bool[]":
|
|
150
156
|
isError = this.isErrorBool(v);
|
|
151
157
|
break;
|
|
158
|
+
case "json[]":
|
|
159
|
+
case "jsonb[]":
|
|
160
|
+
isError = this.isErrorJson(v);
|
|
161
|
+
break;
|
|
152
162
|
default:
|
|
153
163
|
throw new Error(`The specified ColumnTypeEnum does not exist. (${columnType})`);
|
|
154
164
|
}
|
|
@@ -173,6 +183,9 @@ class ValidateValueUtil {
|
|
|
173
183
|
return this.isErrorNumber(value);
|
|
174
184
|
case "bool":
|
|
175
185
|
return this.isErrorBool(value);
|
|
186
|
+
case "json":
|
|
187
|
+
case "jsonb":
|
|
188
|
+
return this.isErrorJson(value);
|
|
176
189
|
default:
|
|
177
190
|
throw new Error(`The specified ColumnTypeEnum does not exist. (${columnType})`);
|
|
178
191
|
}
|
|
@@ -246,5 +259,20 @@ class ValidateValueUtil {
|
|
|
246
259
|
}
|
|
247
260
|
return true;
|
|
248
261
|
}
|
|
262
|
+
static isErrorJson(value) {
|
|
263
|
+
if (typeof value === 'object' && value !== null && Array.isArray(value) === false) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
if (typeof value === 'string') {
|
|
267
|
+
try {
|
|
268
|
+
JSON.parse(value);
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
catch (_a) {
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
249
277
|
}
|
|
250
278
|
exports.default = ValidateValueUtil;
|
|
@@ -76,7 +76,11 @@ class WhereExpression {
|
|
|
76
76
|
time: ["=", "!=", ">", ">=", "<", "<="],
|
|
77
77
|
'time[]': [],
|
|
78
78
|
timestamp: ["=", "!=", ">", ">=", "<", "<="],
|
|
79
|
-
'timestamp[]': []
|
|
79
|
+
'timestamp[]': [],
|
|
80
|
+
json: [],
|
|
81
|
+
'json[]': [],
|
|
82
|
+
jsonb: [],
|
|
83
|
+
'jsonb[]': []
|
|
80
84
|
};
|
|
81
85
|
if (useableOperator[leftColumn.type].includes(operator) == false) {
|
|
82
86
|
throw new Error(`The ${operator} operator cannot be used for ${leftColumn.tableName}.${leftColumn.columnName}. (${leftColumn.type})`);
|
package/dist/models/TableDoc.js
CHANGED
|
@@ -331,11 +331,17 @@ function toColumnType(column) {
|
|
|
331
331
|
else if (column.type.startsWith('string')) {
|
|
332
332
|
return column.type.replace('string', `VARCHAR(${column.length})`);
|
|
333
333
|
}
|
|
334
|
+
else if (column.type.startsWith('timestamp')) {
|
|
335
|
+
return column.type.replace('timestamp', 'TIMESTAMP');
|
|
336
|
+
}
|
|
334
337
|
else if (column.type.startsWith('time')) {
|
|
335
338
|
return column.type.replace('time', 'TIME');
|
|
336
339
|
}
|
|
337
|
-
else if (column.type.startsWith('
|
|
338
|
-
return column.type.replace('
|
|
340
|
+
else if (column.type.startsWith('jsonb')) {
|
|
341
|
+
return column.type.replace('jsonb', 'JSONB');
|
|
342
|
+
}
|
|
343
|
+
else if (column.type.startsWith('json')) {
|
|
344
|
+
return column.type.replace('json', 'JSON');
|
|
339
345
|
}
|
|
340
346
|
return '';
|
|
341
347
|
}
|
|
@@ -123,6 +123,10 @@ class TableModel {
|
|
|
123
123
|
'time[]': '{name} should be entered as an array of times in "hh:mi" format or "hh:mi:ss" format.',
|
|
124
124
|
'timestamp': '{name} should be entered in "YYYY-MM-DD" format, "YYYY-MM-DD hh:mi:ss" format, "YYYY-MM-DDThh:mi:ss" format, or as a Date type.',
|
|
125
125
|
'timestamp[]': '{name} should be entered as an array of timestamps in "YYYY-MM-DD" format, "YYYY-MM-DD hh:mi:ss" format, "YYYY-MM-DDThh:mi:ss" format, or as Date types.',
|
|
126
|
+
'json': '{name} should be entered as an Object or JSON string.',
|
|
127
|
+
'json[]': '{name} should be entered as an array of Objects or JSON strings.',
|
|
128
|
+
'jsonb': '{name} should be entered as an Object or JSON string.',
|
|
129
|
+
'jsonb[]': '{name} should be entered as an array of Objects or JSON strings.',
|
|
126
130
|
'length': '{name} should be entered within {length} characters.',
|
|
127
131
|
'null': '{name} is not allowed to be null.',
|
|
128
132
|
'notInput': 'Please enter {name}.',
|
|
@@ -144,6 +148,10 @@ class TableModel {
|
|
|
144
148
|
'time[]': '{name}は"hh:mi"形式または"hh:mi:ss"形式の配列で入力してください。',
|
|
145
149
|
'timestamp': '{name}は"YYYY-MM-DD"形式、"YYYY-MM-DD hh:mi:ss"形式、"YYYY-MM-DDThh:mi:ss"形式、またはDate型で入力してください。',
|
|
146
150
|
'timestamp[]': '{name}は"YYYY-MM-DD"形式、"YYYY-MM-DD hh:mi:ss"形式、"YYYY-MM-DDThh:mi:ss"形式、またはDate型の配列で入力してください。',
|
|
151
|
+
'json': '{name}はObject形またはJSON文字列で入力してください。',
|
|
152
|
+
'json[]': '{name}はObject形またはJSON文字列の配列で入力してください。',
|
|
153
|
+
'jsonb': '{name}はObject形またはJSON文字列で入力してください。',
|
|
154
|
+
'jsonb[]': '{name}はObject形またはJSON文字列の配列で入力してください。',
|
|
147
155
|
'length': '{name}は{length}文字以内で入力してください。',
|
|
148
156
|
'null': '{name}はnullを許可されていません。',
|
|
149
157
|
'notInput': '{name}を入力してください。',
|
|
@@ -35,10 +35,10 @@ class ValidateClient {
|
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
validateInList(
|
|
38
|
+
validateInList(options, key, list, error) {
|
|
39
39
|
var _a, _b;
|
|
40
40
|
const column = this.model.getColumn(key);
|
|
41
|
-
const value =
|
|
41
|
+
const value = options[key];
|
|
42
42
|
if (value === undefined || value === null || value === "") {
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
@@ -54,10 +54,10 @@ class ValidateClient {
|
|
|
54
54
|
throw new Exception_1.UnprocessableException(code, message);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
validateUnderNow(
|
|
57
|
+
validateUnderNow(options, key, error) {
|
|
58
58
|
var _a, _b;
|
|
59
59
|
const column = this.model.getColumn(key);
|
|
60
|
-
const value =
|
|
60
|
+
const value = options[key];
|
|
61
61
|
if (value === undefined || value === null || value === "") {
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
@@ -77,10 +77,10 @@ class ValidateClient {
|
|
|
77
77
|
throw new Exception_1.UnprocessableException(code, message);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
validateUnderToday(
|
|
80
|
+
validateUnderToday(options, key, isErrorToday, error) {
|
|
81
81
|
var _a, _b;
|
|
82
82
|
const column = this.model.getColumn(key);
|
|
83
|
-
const value =
|
|
83
|
+
const value = options[key];
|
|
84
84
|
if (value === undefined || value === null || value === "") {
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
@@ -113,10 +113,10 @@ class ValidateClient {
|
|
|
113
113
|
throw new Exception_1.UnprocessableException(code, message);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
validateRegExp(
|
|
116
|
+
validateRegExp(options, key, regExp, error) {
|
|
117
117
|
var _a, _b;
|
|
118
118
|
const column = this.model.getColumn(key);
|
|
119
|
-
const value =
|
|
119
|
+
const value = options[key];
|
|
120
120
|
if (value === undefined || value === null || value === "") {
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
@@ -137,10 +137,10 @@ class ValidateClient {
|
|
|
137
137
|
throw new Exception_1.UnprocessableException(code, message);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
-
validatePositiveNumber(
|
|
140
|
+
validatePositiveNumber(options, key, error) {
|
|
141
141
|
var _a, _b;
|
|
142
142
|
const column = this.model.getColumn(key);
|
|
143
|
-
const value =
|
|
143
|
+
const value = options[key];
|
|
144
144
|
if (value === undefined || value === null || value === "") {
|
|
145
145
|
return;
|
|
146
146
|
}
|
package/index.d.ts
CHANGED
|
@@ -3,19 +3,24 @@ import { Request, Response } from 'express';
|
|
|
3
3
|
import { Pool, PoolClient } from 'pg';
|
|
4
4
|
import { ErrorMessageType, IncomingHttpHeaders } from './src/reqestResponse/RequestType';
|
|
5
5
|
import { ArrayType, EnumType, ObjectType, PrimitiveType } from './src/reqestResponse/ReqResType';
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
import { MethodType } from './src/Service';
|
|
8
|
+
export { MethodType } from './src/Service';
|
|
9
|
+
|
|
7
10
|
import { Base64Client } from './src/clients/Base64Client';
|
|
8
11
|
import { StringClient } from './src/clients/StringClient';
|
|
9
12
|
import { EncryptClient } from './src/clients/EncryptClient';
|
|
10
13
|
|
|
14
|
+
import { AwsS3Client } from './src/clients/AwsS3Client';
|
|
11
15
|
export { AwsS3Client } from './src/clients/AwsS3Client';
|
|
12
16
|
|
|
13
17
|
// models class
|
|
14
18
|
import ValidateClient from './src/models/ValidateClient';
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
import { TColumnAttribute, TColumnType, TColumnArrayType, TColumn, TColumnDetail, TOperator, TColumnInfo, TQuery, TSelectExpression, TAggregateFuncType, TCondition, TNestedCondition, TSortKeyword, TKeyFormat } from './src/models/Type';
|
|
21
|
+
export { TColumnAttribute, TColumnType, TColumnArrayType, TColumn, TColumnDetail, TOperator, TColumnInfo, TQuery, TSelectExpression, TAggregateFuncType, TCondition, TNestedCondition, TSortKeyword, TKeyFormat } from './src/models/Type';
|
|
18
22
|
|
|
23
|
+
declare module 'pg-mvc-service' {
|
|
19
24
|
export class Service {
|
|
20
25
|
protected readonly method: MethodType;
|
|
21
26
|
get Method(): MethodType;
|
|
@@ -67,7 +72,7 @@ declare module 'pg-mvc-service' {
|
|
|
67
72
|
get EncryptClient(): EncryptClient;
|
|
68
73
|
|
|
69
74
|
public requestApi<TRequest=Record<string, any>, TResponse={[key: string]: any}>(
|
|
70
|
-
method:
|
|
75
|
+
method: MethodType, url: string, params: TRequest, header: {[key: string]: any}): Promise<AxiosResponse<TResponse>>;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
export interface IParams {
|
|
@@ -138,59 +143,6 @@ declare module 'pg-mvc-service' {
|
|
|
138
143
|
constructor(errorId: string, message?: string);
|
|
139
144
|
}
|
|
140
145
|
|
|
141
|
-
export type TSqlValue = string | number | boolean | Date | null | Array<string | null> | Array<number | null> | Array<Date | null> | Array<Boolean | null>;
|
|
142
|
-
|
|
143
|
-
// column type
|
|
144
|
-
export type TColumnAttribute = "primary" | "nullable" | "hasDefault" | "noDefault";
|
|
145
|
-
export type TColumnType = "number" | "string" | "uuid" | "date" | "time" | "timestamp" | "bool";
|
|
146
|
-
export type TColumnArrayType = "number[]" | "string[]" | "uuid[]" | "date[]" | "time[]" | "timestamp[]" | "bool[]";
|
|
147
|
-
type TColumnBase = {
|
|
148
|
-
alias?: string,
|
|
149
|
-
type: TColumnType | TColumnArrayType,
|
|
150
|
-
attribute: TColumnAttribute,
|
|
151
|
-
default?: string,
|
|
152
|
-
comment?: string
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
type TStringColumn = TColumnBase & {
|
|
156
|
-
type: "string",
|
|
157
|
-
length: number
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
type TNonStringColumn = TColumnBase & {
|
|
161
|
-
type: Exclude<TColumnType, "string">,
|
|
162
|
-
length?: undefined
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
type TStringArrayColumn = TColumnBase & {
|
|
166
|
-
type: "string[]",
|
|
167
|
-
length: number,
|
|
168
|
-
attribute: Exclude<TColumnAttribute, "primary">
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
type TArrayColumn = TColumnBase & {
|
|
172
|
-
type: Exclude<TColumnArrayType, "string[]">,
|
|
173
|
-
length?: undefined,
|
|
174
|
-
attribute: Exclude<TColumnAttribute, "primary">
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
export type TColumn = TStringColumn | TNonStringColumn | TStringArrayColumn | TArrayColumn;
|
|
178
|
-
|
|
179
|
-
export type TOperator = "=" | "!=" | ">" | ">=" | "<" | "<=" | "like" | "ilike" | "h2f_like" | "h2f_ilike" | "in" | "not in";
|
|
180
|
-
export type TColumnInfo = { model: TableModel, name: string }
|
|
181
|
-
export type TQuery = {sql: string, vars?: Array<any>};
|
|
182
|
-
export type TSelectExpression = { expression: string, alias: string }
|
|
183
|
-
export type TAggregateFuncType = 'sum' | 'avg' | 'max' | 'min' | 'count';
|
|
184
|
-
export type TCondition = string | {
|
|
185
|
-
l: string | TColumnInfo,
|
|
186
|
-
o: TOperator,
|
|
187
|
-
r: TSqlValue | Array<TSqlValue> | TColumnInfo
|
|
188
|
-
};
|
|
189
|
-
export type TNestedCondition = TCondition | ['AND' | 'OR', ...TNestedCondition[]] | TNestedCondition[];
|
|
190
|
-
export type TSortKeyword = 'desc' | 'asc';
|
|
191
|
-
export type TKeyFormat = 'snake' | 'lowerCamel';
|
|
192
|
-
export type TOption = {[key: string]: TSqlValue};
|
|
193
|
-
|
|
194
146
|
export class TableModel {
|
|
195
147
|
protected readonly dbName: string;
|
|
196
148
|
get DbName(): string;
|
|
@@ -229,8 +181,8 @@ declare module 'pg-mvc-service' {
|
|
|
229
181
|
|
|
230
182
|
public where(expression: string): void;
|
|
231
183
|
public where(conditions: Array<TNestedCondition>): void;
|
|
232
|
-
public where(left: string, operator: TOperator, right:
|
|
233
|
-
public where(left: TColumnInfo, operator: TOperator, right:
|
|
184
|
+
public where(left: string, operator: TOperator, right: any | TColumnInfo): void;
|
|
185
|
+
public where(left: TColumnInfo, operator: TOperator, right: any | TColumnInfo): void;
|
|
234
186
|
|
|
235
187
|
public find<T = {[key: string]: any}>(pk: {[key: string]: any}, selectColumns: Array<string> | "*" | null, selectExpressions: Array<TSelectExpression> | null, keyFormat: TKeyFormat): Promise<T | null>;
|
|
236
188
|
public find<T = {[key: string]: any}>(pk: {[key: string]: any}, selectColumns: Array<string> | "*" | null, selectExpressions: Array<TSelectExpression> | null): Promise<T | null>;
|
|
@@ -244,16 +196,16 @@ declare module 'pg-mvc-service' {
|
|
|
244
196
|
|
|
245
197
|
protected readonly errorMessages: Record<TColumnType | 'length' | 'null' | 'notInput', string>
|
|
246
198
|
protected throwValidationError(code: string, message: string): never;
|
|
247
|
-
protected validateOptions(options:
|
|
248
|
-
protected validateInsert(options:
|
|
249
|
-
protected validateUpdate(options:
|
|
250
|
-
protected validateUpdateId(id: any, options:
|
|
199
|
+
protected validateOptions(options: {[key: string]: any}, isInsert: boolean) : Promise<void>;
|
|
200
|
+
protected validateInsert(options: {[key: string]: any}) : Promise<void>;
|
|
201
|
+
protected validateUpdate(options: {[key: string]: any}) : Promise<void>;
|
|
202
|
+
protected validateUpdateId(id: any, options: {[key: string]: any}) : Promise<void>;
|
|
251
203
|
protected validateDelete() : Promise<void>;
|
|
252
204
|
protected validateDeleteId(id: any) : Promise<void>;
|
|
253
205
|
|
|
254
|
-
public executeInsert(options:
|
|
255
|
-
public executeUpdate(options:
|
|
256
|
-
public executeUpdateId(id: any, options:
|
|
206
|
+
public executeInsert(options: {[key: string]: any}) : Promise<void>;
|
|
207
|
+
public executeUpdate(options: {[key: string]: any}) : Promise<number>;
|
|
208
|
+
public executeUpdateId(id: any, options: {[key: string]: any}) : Promise<void>;
|
|
257
209
|
public executeDelete() : Promise<number>;
|
|
258
210
|
public executeDeleteId(id: any) : Promise<void>;
|
|
259
211
|
|
package/package.json
CHANGED
package/src/Service.ts
CHANGED
|
@@ -218,7 +218,7 @@ export class Service {
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
public async requestApi<TRequest=Record<string, any>, TResponse={[key: string]: any}>(
|
|
221
|
-
method:
|
|
221
|
+
method: MethodType, url: string, params: TRequest, header: {[key: string]: any}): Promise<AxiosResponse<TResponse>> {
|
|
222
222
|
|
|
223
223
|
// GET,DELETEのparamをURLクエリに
|
|
224
224
|
if (method === 'GET' || method === 'DELETE') {
|
|
@@ -127,6 +127,12 @@ export default class ValidateValueUtil {
|
|
|
127
127
|
throw new Error('Please enter a value of type bool, or a string "true" or "false", or a number 0 or 1.');
|
|
128
128
|
}
|
|
129
129
|
break;
|
|
130
|
+
case "json":
|
|
131
|
+
case "jsonb":
|
|
132
|
+
if (this.isErrorJson(value)) {
|
|
133
|
+
throw new Error('Please enter a value as an Object or JSON string.');
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
138
|
|
|
@@ -162,6 +168,10 @@ export default class ValidateValueUtil {
|
|
|
162
168
|
case "bool[]":
|
|
163
169
|
isError = this.isErrorBool(v);
|
|
164
170
|
break;
|
|
171
|
+
case "json[]":
|
|
172
|
+
case "jsonb[]":
|
|
173
|
+
isError = this.isErrorJson(v);
|
|
174
|
+
break;
|
|
165
175
|
default:
|
|
166
176
|
throw new Error(`The specified ColumnTypeEnum does not exist. (${columnType})`);
|
|
167
177
|
}
|
|
@@ -189,6 +199,9 @@ export default class ValidateValueUtil {
|
|
|
189
199
|
return this.isErrorNumber(value);
|
|
190
200
|
case "bool":
|
|
191
201
|
return this.isErrorBool(value);
|
|
202
|
+
case "json":
|
|
203
|
+
case "jsonb":
|
|
204
|
+
return this.isErrorJson(value);
|
|
192
205
|
default:
|
|
193
206
|
throw new Error(`The specified ColumnTypeEnum does not exist. (${columnType})`);
|
|
194
207
|
}
|
|
@@ -267,4 +280,21 @@ export default class ValidateValueUtil {
|
|
|
267
280
|
|
|
268
281
|
return true;
|
|
269
282
|
}
|
|
283
|
+
|
|
284
|
+
static isErrorJson(value: any): boolean {
|
|
285
|
+
if (typeof value === 'object' && value !== null && Array.isArray(value) === false) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (typeof value === 'string') {
|
|
290
|
+
try {
|
|
291
|
+
JSON.parse(value);
|
|
292
|
+
return false;
|
|
293
|
+
} catch {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
270
300
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TableModel } from "../TableModel";
|
|
2
|
-
import { TColumnArrayType, TColumnDetail, TColumnInfo, TColumnType, TNestedCondition, TOperator, TQuery
|
|
2
|
+
import { TColumnArrayType, TColumnDetail, TColumnInfo, TColumnType, TNestedCondition, TOperator, TQuery } from "../Type";
|
|
3
3
|
import ValidateValueUtil from "./ValidateValueUtil";
|
|
4
4
|
|
|
5
5
|
export default class WhereExpression {
|
|
@@ -66,7 +66,7 @@ export default class WhereExpression {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
public static create(left: TColumnInfo, operator: TOperator, right:
|
|
69
|
+
public static create(left: TColumnInfo, operator: TOperator, right: TColumnInfo | any, varLength: number) : TQuery {
|
|
70
70
|
|
|
71
71
|
// Check if the specified ColumnInfo exists
|
|
72
72
|
const leftColumn = left.model.getColumn(left.name);
|
|
@@ -86,7 +86,11 @@ export default class WhereExpression {
|
|
|
86
86
|
time: ["=", "!=", ">", ">=", "<", "<="],
|
|
87
87
|
'time[]': [],
|
|
88
88
|
timestamp: ["=", "!=", ">", ">=", "<", "<="],
|
|
89
|
-
'timestamp[]': []
|
|
89
|
+
'timestamp[]': [],
|
|
90
|
+
json: [],
|
|
91
|
+
'json[]': [],
|
|
92
|
+
jsonb: [],
|
|
93
|
+
'jsonb[]': []
|
|
90
94
|
};
|
|
91
95
|
|
|
92
96
|
if (useableOperator[leftColumn.type].includes(operator) == false) {
|
|
@@ -118,7 +122,7 @@ export default class WhereExpression {
|
|
|
118
122
|
}
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
private static createExpression(leftColumn: TColumnDetail, operator: TOperator, right:
|
|
125
|
+
private static createExpression(leftColumn: TColumnDetail, operator: TOperator, right: TColumnInfo | any, varLength: number) : TQuery {
|
|
122
126
|
// IN NOT IN clause
|
|
123
127
|
if (["in", "not in"].includes(operator)) {
|
|
124
128
|
if (Array.isArray(right) == false) {
|
|
@@ -192,7 +196,7 @@ export default class WhereExpression {
|
|
|
192
196
|
}
|
|
193
197
|
}
|
|
194
198
|
|
|
195
|
-
private static createExpressionArrayValue(leftColumn: TColumnDetail, operator: TOperator, right:
|
|
199
|
+
private static createExpressionArrayValue(leftColumn: TColumnDetail, operator: TOperator, right: any, varLength: number) : TQuery {
|
|
196
200
|
|
|
197
201
|
// ValidateValueUtil.validateValue(leftColumn, right);
|
|
198
202
|
// LIKE operators are different, so handle separately
|
package/src/models/TableDoc.ts
CHANGED
|
@@ -337,10 +337,14 @@ function toColumnType(column: TColumn) {
|
|
|
337
337
|
return column.type.replace('number', 'INTEGER');
|
|
338
338
|
} else if (column.type.startsWith('string')) {
|
|
339
339
|
return column.type.replace('string', `VARCHAR(${column.length})`);
|
|
340
|
-
} else if (column.type.startsWith('time')) {
|
|
341
|
-
return column.type.replace('time', 'TIME');
|
|
342
340
|
} else if (column.type.startsWith('timestamp')) {
|
|
343
341
|
return column.type.replace('timestamp', 'TIMESTAMP');
|
|
342
|
+
} else if (column.type.startsWith('time')) {
|
|
343
|
+
return column.type.replace('time', 'TIME');
|
|
344
|
+
} else if (column.type.startsWith('jsonb')) {
|
|
345
|
+
return column.type.replace('jsonb', 'JSONB');
|
|
346
|
+
} else if (column.type.startsWith('json')) {
|
|
347
|
+
return column.type.replace('json', 'JSON');
|
|
344
348
|
}
|
|
345
349
|
|
|
346
350
|
return '';
|
package/src/models/TableModel.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Pool, PoolClient } from 'pg';
|
|
2
|
-
import { TAggregateFuncType, TColumn, TColumnArrayType,
|
|
2
|
+
import { TAggregateFuncType, TColumn, TColumnArrayType, TColumnDetail, TColumnInfo, TColumnType, TKeyFormat, TNestedCondition, TOperator, TQuery, TSelectExpression, TSortKeyword } from "./Type";
|
|
3
3
|
import ValidateValueUtil from './SqlUtils/ValidateValueUtil';
|
|
4
4
|
import SelectExpression from './SqlUtils/SelectExpression';
|
|
5
5
|
import WhereExpression from './SqlUtils/WhereExpression';
|
|
@@ -277,9 +277,9 @@ export class TableModel {
|
|
|
277
277
|
|
|
278
278
|
public where(expression: string): void;
|
|
279
279
|
public where(conditions: Array<TNestedCondition>): void;
|
|
280
|
-
public where(left: string, operator: TOperator, right:
|
|
281
|
-
public where(left: TColumnInfo, operator: TOperator, right:
|
|
282
|
-
public where(left: string | TColumnInfo | Array<TNestedCondition>, operator?: TOperator, right?:
|
|
280
|
+
public where(left: string, operator: TOperator, right: TColumnInfo | any): void;
|
|
281
|
+
public where(left: TColumnInfo, operator: TOperator, right: TColumnInfo | any): void;
|
|
282
|
+
public where(left: string | TColumnInfo | Array<TNestedCondition>, operator?: TOperator, right?: TColumnInfo | any): void {
|
|
283
283
|
if (typeof left === 'string') {
|
|
284
284
|
if (operator === undefined || right === undefined) {
|
|
285
285
|
this.whereExpressions.push(left);
|
|
@@ -416,6 +416,10 @@ export class TableModel {
|
|
|
416
416
|
'time[]': '{name} should be entered as an array of times in "hh:mi" format or "hh:mi:ss" format.',
|
|
417
417
|
'timestamp': '{name} should be entered in "YYYY-MM-DD" format, "YYYY-MM-DD hh:mi:ss" format, "YYYY-MM-DDThh:mi:ss" format, or as a Date type.',
|
|
418
418
|
'timestamp[]': '{name} should be entered as an array of timestamps in "YYYY-MM-DD" format, "YYYY-MM-DD hh:mi:ss" format, "YYYY-MM-DDThh:mi:ss" format, or as Date types.',
|
|
419
|
+
'json': '{name} should be entered as an Object or JSON string.',
|
|
420
|
+
'json[]': '{name} should be entered as an array of Objects or JSON strings.',
|
|
421
|
+
'jsonb': '{name} should be entered as an Object or JSON string.',
|
|
422
|
+
'jsonb[]': '{name} should be entered as an array of Objects or JSON strings.',
|
|
419
423
|
'length': '{name} should be entered within {length} characters.',
|
|
420
424
|
'null': '{name} is not allowed to be null.',
|
|
421
425
|
'notInput': 'Please enter {name}.',
|
|
@@ -437,6 +441,10 @@ export class TableModel {
|
|
|
437
441
|
'time[]': '{name}は"hh:mi"形式または"hh:mi:ss"形式の配列で入力してください。',
|
|
438
442
|
'timestamp': '{name}は"YYYY-MM-DD"形式、"YYYY-MM-DD hh:mi:ss"形式、"YYYY-MM-DDThh:mi:ss"形式、またはDate型で入力してください。',
|
|
439
443
|
'timestamp[]': '{name}は"YYYY-MM-DD"形式、"YYYY-MM-DD hh:mi:ss"形式、"YYYY-MM-DDThh:mi:ss"形式、またはDate型の配列で入力してください。',
|
|
444
|
+
'json': '{name}はObject形またはJSON文字列で入力してください。',
|
|
445
|
+
'json[]': '{name}はObject形またはJSON文字列の配列で入力してください。',
|
|
446
|
+
'jsonb': '{name}はObject形またはJSON文字列で入力してください。',
|
|
447
|
+
'jsonb[]': '{name}はObject形またはJSON文字列の配列で入力してください。',
|
|
440
448
|
'length': '{name}は{length}文字以内で入力してください。',
|
|
441
449
|
'null': '{name}はnullを許可されていません。',
|
|
442
450
|
'notInput': '{name}を入力してください。',
|
|
@@ -444,7 +452,7 @@ export class TableModel {
|
|
|
444
452
|
'idNotExist': '指定されたID({id})はテーブルに存在しません。',
|
|
445
453
|
}
|
|
446
454
|
|
|
447
|
-
private throwException(code: string, type: TColumnType | TColumnArrayType | 'length' | 'null' | 'notInput' | 'fk' | 'idNotExist', columnName: string, vallue:
|
|
455
|
+
private throwException(code: string, type: TColumnType | TColumnArrayType | 'length' | 'null' | 'notInput' | 'fk' | 'idNotExist', columnName: string, vallue: any): never {
|
|
448
456
|
const column = this.getColumn(columnName);
|
|
449
457
|
|
|
450
458
|
let message = this.errorMessages[type];
|
|
@@ -461,7 +469,7 @@ export class TableModel {
|
|
|
461
469
|
protected readonly errorMessages: Record<TColumnType | TColumnArrayType | 'length' | 'null' | 'notInput' | 'fk' | 'idNotExist', string> =
|
|
462
470
|
process.env.TZ === 'Asia/Tokyo' ? this.errorMessageJapan : this.errorMessageEnglish;
|
|
463
471
|
|
|
464
|
-
protected async validateOptions(options:
|
|
472
|
+
protected async validateOptions(options: {[key: string]: any}, isInsert: boolean): Promise<void> {
|
|
465
473
|
if (Object.keys(options).length === 0) {
|
|
466
474
|
throw new Error('At least one key-value pair is required in options.');
|
|
467
475
|
}
|
|
@@ -531,7 +539,7 @@ export class TableModel {
|
|
|
531
539
|
}
|
|
532
540
|
}
|
|
533
541
|
|
|
534
|
-
protected async validateInsert(options:
|
|
542
|
+
protected async validateInsert(options: {[key: string]: any}) : Promise<void> {
|
|
535
543
|
for (const key in this.Columns) {
|
|
536
544
|
const column = this.getColumn(key);
|
|
537
545
|
const name = (column.alias === undefined || column.alias === '') ? key : column.alias;
|
|
@@ -544,12 +552,12 @@ export class TableModel {
|
|
|
544
552
|
}
|
|
545
553
|
}
|
|
546
554
|
|
|
547
|
-
protected async validateUpdate(options:
|
|
548
|
-
protected async validateUpdateId(id: any, options:
|
|
555
|
+
protected async validateUpdate(options: {[key: string]: any}) : Promise<void> { }
|
|
556
|
+
protected async validateUpdateId(id: any, options: {[key: string]: any}) : Promise<void> { }
|
|
549
557
|
protected async validateDelete() : Promise<void> { }
|
|
550
558
|
protected async validateDeleteId(id: any) : Promise<void> { }
|
|
551
559
|
|
|
552
|
-
public async executeInsert(options:
|
|
560
|
+
public async executeInsert(options: {[key: string]: any}) : Promise<void> {
|
|
553
561
|
await this.validateOptions(options, true);
|
|
554
562
|
await this.validateInsert(options);
|
|
555
563
|
|
|
@@ -570,7 +578,7 @@ export class TableModel {
|
|
|
570
578
|
await this.executeQuery(sql, vars);
|
|
571
579
|
}
|
|
572
580
|
|
|
573
|
-
public async executeUpdate(options:
|
|
581
|
+
public async executeUpdate(options: {[key: string]: any}) : Promise<number> {
|
|
574
582
|
await this.validateOptions(options, false);
|
|
575
583
|
await this.validateUpdate(options);
|
|
576
584
|
|
|
@@ -606,7 +614,7 @@ export class TableModel {
|
|
|
606
614
|
return data.rowCount;
|
|
607
615
|
}
|
|
608
616
|
|
|
609
|
-
public async executeUpdateId(id: any, options:
|
|
617
|
+
public async executeUpdateId(id: any, options: {[key: string]: any}) : Promise<void> {
|
|
610
618
|
ValidateValueUtil.validateId(this.Columns, id);
|
|
611
619
|
await this.validateOptions(options, false);
|
|
612
620
|
await this.validateUpdateId(id, options);
|
package/src/models/Type.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { TableModel } from "./TableModel";
|
|
2
|
-
|
|
3
|
-
export type TSqlValue = string | number | boolean | Date | null | Array<string | null> | Array<number | null> | Array<Date | null> | Array<Boolean | null>;
|
|
1
|
+
import type { TableModel } from "./TableModel";
|
|
4
2
|
|
|
5
3
|
// column type
|
|
6
4
|
export type TColumnAttribute = "primary" | "nullable" | "hasDefault" | "noDefault";
|
|
7
|
-
export type TColumnType = "number" | "string" | "uuid" | "date" | "time" | "timestamp" | "bool";
|
|
8
|
-
export type TColumnArrayType = "number[]" | "string[]" | "uuid[]" | "date[]" | "time[]" | "timestamp[]" | "bool[]";
|
|
5
|
+
export type TColumnType = "number" | "string" | "uuid" | "date" | "time" | "timestamp" | "bool" | "json" | "jsonb";
|
|
6
|
+
export type TColumnArrayType = "number[]" | "string[]" | "uuid[]" | "date[]" | "time[]" | "timestamp[]" | "bool[]" | "json[]" | "jsonb[]";
|
|
9
7
|
type TColumnBase = {
|
|
10
8
|
alias?: string,
|
|
11
9
|
type: TColumnType | TColumnArrayType,
|
|
@@ -16,12 +14,18 @@ type TColumnBase = {
|
|
|
16
14
|
|
|
17
15
|
type TStringColumn = TColumnBase & {
|
|
18
16
|
type: "string",
|
|
19
|
-
length: number
|
|
17
|
+
length: number,
|
|
20
18
|
};
|
|
21
19
|
|
|
22
|
-
type
|
|
20
|
+
type TJsonColumn = TColumnBase & {
|
|
21
|
+
type: "json" | "jsonb"
|
|
22
|
+
length?: undefined,
|
|
23
|
+
attribute: Exclude<TColumnAttribute, "primary">
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type TBasicColumn = TColumnBase & {
|
|
23
27
|
type: Exclude<TColumnType, "string">,
|
|
24
|
-
length?: undefined
|
|
28
|
+
length?: undefined,
|
|
25
29
|
};
|
|
26
30
|
|
|
27
31
|
type TStringArrayColumn = TColumnBase & {
|
|
@@ -36,7 +40,7 @@ type TArrayColumn = TColumnBase & {
|
|
|
36
40
|
attribute: Exclude<TColumnAttribute, "primary">
|
|
37
41
|
};
|
|
38
42
|
|
|
39
|
-
export type TColumn = TStringColumn |
|
|
43
|
+
export type TColumn = TStringColumn | TJsonColumn | TBasicColumn | TStringArrayColumn | TArrayColumn;
|
|
40
44
|
export type TColumnDetail = TColumn & {
|
|
41
45
|
columnName: string,
|
|
42
46
|
tableName: string,
|
|
@@ -51,9 +55,8 @@ export type TAggregateFuncType = 'sum' | 'avg' | 'max' | 'min' | 'count';
|
|
|
51
55
|
export type TCondition = string | {
|
|
52
56
|
l: string | TColumnInfo,
|
|
53
57
|
o: TOperator,
|
|
54
|
-
r:
|
|
58
|
+
r: any | TColumnInfo
|
|
55
59
|
};
|
|
56
60
|
export type TNestedCondition = TCondition | ['AND' | 'OR', ...TNestedCondition[]] | TNestedCondition[];
|
|
57
61
|
export type TSortKeyword = 'desc' | 'asc';
|
|
58
|
-
export type TKeyFormat = 'snake' | 'lowerCamel';
|
|
59
|
-
export type TOption = {[key: string]: TSqlValue};
|
|
62
|
+
export type TKeyFormat = 'snake' | 'lowerCamel';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { UnprocessableException } from "../exceptions/Exception";
|
|
2
2
|
import ValidateValueUtil from "./SqlUtils/ValidateValueUtil";
|
|
3
3
|
import { TableModel } from "./TableModel";
|
|
4
|
-
import { TOption, TSqlValue } from "./Type";
|
|
5
4
|
|
|
6
5
|
type TError = {code?: string; message?: string;};
|
|
7
6
|
|
|
@@ -44,9 +43,9 @@ export default class ValidateClient {
|
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
public validateInList(
|
|
46
|
+
public validateInList(options: {[key: string]: any}, key: string, list: Array<number | string | boolean>, error?: TError) {
|
|
48
47
|
const column = this.model.getColumn(key);
|
|
49
|
-
const value =
|
|
48
|
+
const value = options[key];
|
|
50
49
|
if (value === undefined || value === null || value === "") {
|
|
51
50
|
return;
|
|
52
51
|
}
|
|
@@ -64,9 +63,9 @@ export default class ValidateClient {
|
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
public validateUnderNow(
|
|
66
|
+
public validateUnderNow(options: {[key: string]: any}, key: string, error?: TError) {
|
|
68
67
|
const column = this.model.getColumn(key);
|
|
69
|
-
const value =
|
|
68
|
+
const value = options[key];
|
|
70
69
|
if (value === undefined || value === null || value === "") {
|
|
71
70
|
return;
|
|
72
71
|
}
|
|
@@ -89,9 +88,9 @@ export default class ValidateClient {
|
|
|
89
88
|
}
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
public validateUnderToday(
|
|
91
|
+
public validateUnderToday(options: {[key: string]: any}, key: string, isErrorToday: boolean, error?: TError): void {
|
|
93
92
|
const column = this.model.getColumn(key);
|
|
94
|
-
const value =
|
|
93
|
+
const value = options[key];
|
|
95
94
|
if (value === undefined || value === null || value === "") {
|
|
96
95
|
return;
|
|
97
96
|
}
|
|
@@ -128,9 +127,9 @@ export default class ValidateClient {
|
|
|
128
127
|
}
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
public validateRegExp(
|
|
130
|
+
public validateRegExp(options: {[key: string]: any}, key: string, regExp: RegExp | string, error?: TError): void {
|
|
132
131
|
const column = this.model.getColumn(key);
|
|
133
|
-
const value =
|
|
132
|
+
const value = options[key];
|
|
134
133
|
if (value === undefined || value === null || value === "") {
|
|
135
134
|
return;
|
|
136
135
|
}
|
|
@@ -155,9 +154,9 @@ export default class ValidateClient {
|
|
|
155
154
|
}
|
|
156
155
|
}
|
|
157
156
|
|
|
158
|
-
public validatePositiveNumber(
|
|
157
|
+
public validatePositiveNumber(options: {[key: string]: any}, key: string, error?: TError) {
|
|
159
158
|
const column = this.model.getColumn(key);
|
|
160
|
-
const value =
|
|
159
|
+
const value = options[key];
|
|
161
160
|
if (value === undefined || value === null || value === "") {
|
|
162
161
|
return;
|
|
163
162
|
}
|