pg-mvc-service 1.0.15 → 1.0.17

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.
@@ -21,12 +21,6 @@ const createSwagger = (services, name, url, params = []) => {
21
21
  endpontSwaggerYml[service.Endpoint] = {};
22
22
  }
23
23
  let yml = "";
24
- const splitEndpont = service.Endpoint.split('/');
25
- let tagName = splitEndpont[0];
26
- if (tagName === '' && splitEndpont.length > 1) {
27
- tagName = splitEndpont[1];
28
- ;
29
- }
30
24
  const apiTags = service.Tags;
31
25
  if (apiTags.length > 0) {
32
26
  tags = [...tags, ...apiTags];
@@ -38,8 +32,8 @@ const createSwagger = (services, name, url, params = []) => {
38
32
  yml += ` summary: ${service.Summary}\n`;
39
33
  const croneParams = [...params];
40
34
  for (const path of service.Endpoint.split('/')) {
41
- if (path.startsWith(':')) {
42
- const key = path.replace(':', '');
35
+ if (path.startsWith('{') && path.endsWith('}')) {
36
+ const key = path.replace('{', '').replace('}', '');
43
37
  croneParams.push({
44
38
  in: 'path',
45
39
  name: key,
@@ -82,7 +76,7 @@ tags:\n`;
82
76
  }
83
77
  swaggerInfo += 'paths:\n';
84
78
  for (const keyEndpoint in endpontSwaggerYml) {
85
- swaggerInfo += ` ${keyEndpoint.replace(/\/:([^\/]+)/g, '/{$1}')}:\n`;
79
+ swaggerInfo += ` ${keyEndpoint}:\n`;
86
80
  setYmlByMethod('GET', endpontSwaggerYml[keyEndpoint]);
87
81
  setYmlByMethod('POST', endpontSwaggerYml[keyEndpoint]);
88
82
  setYmlByMethod('PUT', endpontSwaggerYml[keyEndpoint]);
@@ -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})`);
@@ -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('timestamp')) {
338
- return column.type.replace('timestamp', 'TIMESTAMP');
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(option, key, list, error) {
38
+ validateInList(options, key, list, error) {
39
39
  var _a, _b;
40
40
  const column = this.model.getColumn(key);
41
- const value = option[key];
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(option, key, error) {
57
+ validateUnderNow(options, key, error) {
58
58
  var _a, _b;
59
59
  const column = this.model.getColumn(key);
60
- const value = option[key];
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(option, key, isErrorToday, error) {
80
+ validateUnderToday(options, key, isErrorToday, error) {
81
81
  var _a, _b;
82
82
  const column = this.model.getColumn(key);
83
- const value = option[key];
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(option, key, regExp, error) {
116
+ validateRegExp(options, key, regExp, error) {
117
117
  var _a, _b;
118
118
  const column = this.model.getColumn(key);
119
- const value = option[key];
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(option, key, error) {
140
+ validatePositiveNumber(options, key, error) {
141
141
  var _a, _b;
142
142
  const column = this.model.getColumn(key);
143
- const value = option[key];
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
- import { AwsS3Client } from './src/clients/AwsS3Client';
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
- declare module 'pg-mvc-service' {
17
- export type MethodType = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
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: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', url: string, params: TRequest, header: {[key: string]: any}): Promise<AxiosResponse<TResponse>>;
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: TSqlValue | Array<TSqlValue> | TColumnInfo | null): void;
233
- public where(left: TColumnInfo, operator: TOperator, right: TSqlValue | Array<TSqlValue> | TColumnInfo | null): void;
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: TOption, isInsert: boolean) : Promise<void>;
248
- protected validateInsert(options: TOption) : Promise<void>;
249
- protected validateUpdate(options: TOption) : Promise<void>;
250
- protected validateUpdateId(id: any, options: TOption) : Promise<void>;
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: TOption) : Promise<void>;
255
- public executeUpdate(options: TOption) : Promise<number>;
256
- public executeUpdateId(id: any, options: TOption) : Promise<void>;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pg-mvc-service",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "",
5
5
  "homepage": "https://github.com/n-daira/npm-pack_mvc-service#readme",
6
6
  "bugs": {
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: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', url: string, params: TRequest, header: {[key: string]: any}): Promise<AxiosResponse<TResponse>> {
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') {
@@ -31,12 +31,6 @@ export const createSwagger = (services: Service[], name: string, url: string, pa
31
31
  }
32
32
  let yml = "";
33
33
 
34
- const splitEndpont = service.Endpoint.split('/');
35
- let tagName = splitEndpont[0];
36
- if (tagName === '' && splitEndpont.length > 1) {
37
- tagName = splitEndpont[1];;
38
- }
39
-
40
34
  const apiTags = service.Tags;
41
35
  if (apiTags.length > 0) {
42
36
  tags = [ ...tags, ...apiTags];
@@ -49,8 +43,8 @@ export const createSwagger = (services: Service[], name: string, url: string, pa
49
43
 
50
44
  const croneParams = [...params];
51
45
  for (const path of service.Endpoint.split('/')) {
52
- if (path.startsWith(':')) {
53
- const key = path.replace(':', '');
46
+ if (path.startsWith('{') && path.endsWith('}')) {
47
+ const key = path.replace('{', '').replace('}', '');
54
48
  croneParams.push({
55
49
  in: 'path',
56
50
  name: key,
@@ -98,7 +92,7 @@ tags:\n`;
98
92
  swaggerInfo += 'paths:\n'
99
93
 
100
94
  for (const keyEndpoint in endpontSwaggerYml) {
101
- swaggerInfo += ` ${keyEndpoint.replace(/\/:([^\/]+)/g, '/{$1}')}:\n`;
95
+ swaggerInfo += ` ${keyEndpoint}:\n`;
102
96
 
103
97
  setYmlByMethod('GET', endpontSwaggerYml[keyEndpoint]);
104
98
  setYmlByMethod('POST', endpontSwaggerYml[keyEndpoint]);
@@ -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, TSqlValue } from "../Type";
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: TSqlValue | null | Array<TSqlValue> | TColumnInfo, varLength: number) : TQuery {
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: TSqlValue | Array<TSqlValue> | TColumnInfo, varLength: number) : TQuery {
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: TSqlValue | Array<TSqlValue>, varLength: number) : TQuery {
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
@@ -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 '';
@@ -1,5 +1,5 @@
1
1
  import { Pool, PoolClient } from 'pg';
2
- import { TAggregateFuncType, TColumn, TColumnArrayType, TColumnAttribute, TColumnDetail, TColumnInfo, TColumnType, TKeyFormat, TNestedCondition, TOperator, TOption, TQuery, TSelectExpression, TSortKeyword, TSqlValue } from "./Type";
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: TSqlValue | Array<TSqlValue> | TColumnInfo | null): void;
281
- public where(left: TColumnInfo, operator: TOperator, right: TSqlValue | Array<TSqlValue> | TColumnInfo | null): void;
282
- public where(left: string | TColumnInfo | Array<TNestedCondition>, operator?: TOperator, right?: TSqlValue | Array<TSqlValue> | TColumnInfo | null): void {
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: TSqlValue): never {
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: TOption, isInsert: boolean): Promise<void> {
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: TOption) : Promise<void> {
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: TOption) : Promise<void> { }
548
- protected async validateUpdateId(id: any, options: TOption) : Promise<void> { }
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: TOption) : Promise<void> {
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: TOption) : Promise<number> {
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: TOption) : Promise<void> {
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);
@@ -1,11 +1,9 @@
1
1
  import { TableModel } from "./TableModel";
2
2
 
3
- export type TSqlValue = string | number | boolean | Date | null | Array<string | null> | Array<number | null> | Array<Date | null> | Array<Boolean | null>;
4
-
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 TNonStringColumn = TColumnBase & {
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 | TNonStringColumn | TStringArrayColumn | TArrayColumn;
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: TSqlValue | Array<TSqlValue> | TColumnInfo
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(option: TOption, key: string, list: Array<TSqlValue>, error?: TError) {
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 = option[key];
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(option: TOption, key: string, error?: TError) {
66
+ public validateUnderNow(options: {[key: string]: any}, key: string, error?: TError) {
68
67
  const column = this.model.getColumn(key);
69
- const value = option[key];
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(option: TOption, key: string, isErrorToday: boolean, error?: TError): void {
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 = option[key];
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(option: TOption, key: string, regExp: RegExp | string, error?: TError): void {
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 = option[key];
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(option: TOption, key: string, error?: TError) {
157
+ public validatePositiveNumber(options: {[key: string]: any}, key: string, error?: TError) {
159
158
  const column = this.model.getColumn(key);
160
- const value = option[key];
159
+ const value = options[key];
161
160
  if (value === undefined || value === null || value === "") {
162
161
  return;
163
162
  }