evaengine 1.0.14 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -7
- package/bin/engine +2 -31
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +32 -0
- package/dist/bin.js.map +1 -0
- package/{src/commands/index.js → dist/commands/index.d.ts} +1 -8
- package/dist/commands/index.js +6 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/interface.d.ts +18 -0
- package/dist/commands/interface.js +40 -0
- package/dist/commands/interface.js.map +1 -0
- package/dist/commands/make_entity.d.ts +47 -0
- package/dist/commands/make_entity.js +410 -0
- package/dist/commands/make_entity.js.map +1 -0
- package/dist/commands/tramp.d.ts +7 -0
- package/dist/commands/tramp.js +29 -0
- package/dist/commands/tramp.js.map +1 -0
- package/dist/config/index.d.ts +92 -0
- package/dist/config/index.js +96 -0
- package/dist/config/index.js.map +1 -0
- package/dist/di.d.ts +131 -0
- package/dist/di.js +197 -0
- package/dist/di.js.map +1 -0
- package/dist/engine.d.ts +85 -0
- package/dist/engine.js +404 -0
- package/dist/engine.js.map +1 -0
- package/dist/entities/index.d.ts +54 -0
- package/dist/entities/index.js +228 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/exceptions/index.d.ts +153 -0
- package/dist/exceptions/index.js +466 -0
- package/dist/exceptions/index.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/middlewares/auth.d.ts +5 -0
- package/dist/middlewares/auth.js +63 -0
- package/dist/middlewares/auth.js.map +1 -0
- package/dist/middlewares/auth_kong.d.ts +2 -0
- package/dist/middlewares/auth_kong.js +24 -0
- package/dist/middlewares/auth_kong.js.map +1 -0
- package/dist/middlewares/debug.d.ts +3 -0
- package/dist/middlewares/debug.js +50 -0
- package/dist/middlewares/debug.js.map +1 -0
- package/{src/middlewares/index.js → dist/middlewares/index.d.ts} +1 -11
- package/dist/middlewares/index.js +9 -0
- package/dist/middlewares/index.js.map +1 -0
- package/dist/middlewares/providers.d.ts +25 -0
- package/dist/middlewares/providers.js +63 -0
- package/dist/middlewares/providers.js.map +1 -0
- package/dist/middlewares/session.d.ts +5 -0
- package/dist/middlewares/session.js +46 -0
- package/dist/middlewares/session.js.map +1 -0
- package/dist/middlewares/trace.d.ts +52 -0
- package/dist/middlewares/trace.js +225 -0
- package/dist/middlewares/trace.js.map +1 -0
- package/dist/middlewares/validator.d.ts +10 -0
- package/dist/middlewares/validator.js +43 -0
- package/dist/middlewares/validator.js.map +1 -0
- package/dist/middlewares/view_cache.d.ts +14 -0
- package/dist/middlewares/view_cache.js +102 -0
- package/dist/middlewares/view_cache.js.map +1 -0
- package/dist/services/cache.d.ts +68 -0
- package/dist/services/cache.js +206 -0
- package/dist/services/cache.js.map +1 -0
- package/dist/services/config.d.ts +17 -0
- package/dist/services/config.js +67 -0
- package/dist/services/config.js.map +1 -0
- package/dist/services/env.d.ts +12 -0
- package/dist/services/env.js +24 -0
- package/dist/services/env.js.map +1 -0
- package/dist/services/event_manager.d.ts +30 -0
- package/dist/services/event_manager.js +74 -0
- package/dist/services/event_manager.js.map +1 -0
- package/dist/services/http_client.d.ts +67 -0
- package/dist/services/http_client.js +61 -0
- package/dist/services/http_client.js.map +1 -0
- package/{src/services/index.js → dist/services/index.d.ts} +1 -15
- package/dist/services/index.js +14 -0
- package/dist/services/index.js.map +1 -0
- package/{src/services/interface.js → dist/services/interface.d.ts} +1 -3
- package/dist/services/interface.js +6 -0
- package/dist/services/interface.js.map +1 -0
- package/{src/services/joi.js → dist/services/joi.d.ts} +2 -9
- package/dist/services/joi.js +11 -0
- package/dist/services/joi.js.map +1 -0
- package/dist/services/jwt_token.d.ts +25 -0
- package/dist/services/jwt_token.js +76 -0
- package/dist/services/jwt_token.js.map +1 -0
- package/dist/services/jwt_token_kong.d.ts +26 -0
- package/dist/services/jwt_token_kong.js +64 -0
- package/dist/services/jwt_token_kong.js.map +1 -0
- package/dist/services/logger.d.ts +31 -0
- package/dist/services/logger.js +125 -0
- package/dist/services/logger.js.map +1 -0
- package/dist/services/namespace.d.ts +62 -0
- package/dist/services/namespace.js +171 -0
- package/dist/services/namespace.js.map +1 -0
- package/dist/services/now.d.ts +15 -0
- package/dist/services/now.js +42 -0
- package/dist/services/now.js.map +1 -0
- package/dist/services/providers.d.ts +55 -0
- package/dist/services/providers.js +134 -0
- package/dist/services/providers.js.map +1 -0
- package/dist/services/redis.d.ts +19 -0
- package/dist/services/redis.js +52 -0
- package/dist/services/redis.js.map +1 -0
- package/dist/services/rest_client.d.ts +49 -0
- package/dist/services/rest_client.js +95 -0
- package/dist/services/rest_client.js.map +1 -0
- package/dist/swagger/index.d.ts +223 -0
- package/dist/swagger/index.js +564 -0
- package/dist/swagger/index.js.map +1 -0
- package/dist/types/express.d.ts +14 -0
- package/dist/types/vendor.d.ts +30 -0
- package/dist/utils/api_scaffold.d.ts +74 -0
- package/dist/utils/api_scaffold.js +220 -0
- package/dist/utils/api_scaffold.js.map +1 -0
- package/dist/utils/case_converter.d.ts +7 -0
- package/dist/utils/case_converter.js +29 -0
- package/dist/utils/case_converter.js.map +1 -0
- package/dist/utils/crc32.d.ts +2 -0
- package/dist/utils/crc32.js +43 -0
- package/dist/utils/crc32.js.map +1 -0
- package/dist/utils/cron.d.ts +27 -0
- package/dist/utils/cron.js +186 -0
- package/dist/utils/cron.js.map +1 -0
- package/dist/utils/datetime.d.ts +4 -0
- package/dist/utils/datetime.js +6 -0
- package/dist/utils/datetime.js.map +1 -0
- package/dist/utils/host.d.ts +18 -0
- package/dist/utils/host.js +33 -0
- package/dist/utils/host.js.map +1 -0
- package/{src/utils/index.js → dist/utils/index.d.ts} +2 -26
- package/dist/utils/index.js +12 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/jwt.d.ts +16 -0
- package/dist/utils/jwt.js +93 -0
- package/dist/utils/jwt.js.map +1 -0
- package/dist/utils/pagination.d.ts +150 -0
- package/dist/utils/pagination.js +242 -0
- package/dist/utils/pagination.js.map +1 -0
- package/dist/utils/random.d.ts +3 -0
- package/dist/utils/random.js +18 -0
- package/dist/utils/random.js.map +1 -0
- package/dist/utils/request_client.d.ts +33 -0
- package/dist/utils/request_client.js +153 -0
- package/dist/utils/request_client.js.map +1 -0
- package/dist/utils/smart_query.d.ts +144 -0
- package/dist/utils/smart_query.js +310 -0
- package/dist/utils/smart_query.js.map +1 -0
- package/dist/utils/test.d.ts +14 -0
- package/dist/utils/test.js +37 -0
- package/dist/utils/test.js.map +1 -0
- package/dist/utils/wrapper.d.ts +3 -0
- package/dist/utils/wrapper.js +5 -0
- package/dist/utils/wrapper.js.map +1 -0
- package/package.json +22 -15
- package/index.js +0 -2
- package/src/commands/interface.js +0 -45
- package/src/commands/make_entity.js +0 -490
- package/src/commands/tramp.js +0 -34
- package/src/config/index.js +0 -95
- package/src/di.js +0 -96
- package/src/engine.js +0 -556
- package/src/entities/index.js +0 -272
- package/src/exceptions/index.js +0 -501
- package/src/index.js +0 -55
- package/src/middlewares/auth.js +0 -67
- package/src/middlewares/auth_kong.js +0 -28
- package/src/middlewares/debug.js +0 -88
- package/src/middlewares/providers.js +0 -73
- package/src/middlewares/session.js +0 -63
- package/src/middlewares/trace.js +0 -254
- package/src/middlewares/validator.js +0 -50
- package/src/middlewares/view_cache.js +0 -127
- package/src/services/cache.js +0 -223
- package/src/services/config.js +0 -115
- package/src/services/env.js +0 -28
- package/src/services/event_manager.js +0 -84
- package/src/services/http_client.js +0 -69
- package/src/services/jwt_token.js +0 -89
- package/src/services/jwt_token_kong.js +0 -75
- package/src/services/logger.js +0 -150
- package/src/services/namespace.js +0 -176
- package/src/services/now.js +0 -49
- package/src/services/providers.js +0 -158
- package/src/services/redis.js +0 -63
- package/src/services/rest_client.js +0 -112
- package/src/swagger/index.js +0 -665
- package/src/utils/api_scaffold.js +0 -240
- package/src/utils/case_converter.js +0 -33
- package/src/utils/crc32.js +0 -44
- package/src/utils/cron.js +0 -208
- package/src/utils/datetime.js +0 -13
- package/src/utils/host.js +0 -39
- package/src/utils/pagination.js +0 -260
- package/src/utils/random.js +0 -23
- package/src/utils/request_client.js +0 -179
- package/src/utils/smart_query.js +0 -352
- package/src/utils/test.js +0 -48
- package/src/utils/wrapper.js +0 -8
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A request-promise-native compatible HTTP client built on the global fetch.
|
|
3
|
+
*
|
|
4
|
+
* Keeps the option object and error shape used by the legacy `request`
|
|
5
|
+
* ecosystem so callers of HttpClient/RestClient see no interface change:
|
|
6
|
+
* - resolves with the response body (or the full response with
|
|
7
|
+
* `resolveWithFullResponse`)
|
|
8
|
+
* - rejects with an error carrying `.name` (`StatusCodeError`/`RequestError`),
|
|
9
|
+
* `.statusCode`, `.response` and `.request`
|
|
10
|
+
* - supports `url`, `method`, `headers`, `body`, `json`, `qs`, `form`,
|
|
11
|
+
* `formData`, `simple`, `resolveWithFullResponse` and `timeout`
|
|
12
|
+
*/
|
|
13
|
+
type RequestClientParams = {
|
|
14
|
+
url?: string;
|
|
15
|
+
method?: string;
|
|
16
|
+
headers?: Record<string, unknown>;
|
|
17
|
+
body?: unknown;
|
|
18
|
+
json?: unknown;
|
|
19
|
+
qs?: Record<string, unknown> | string;
|
|
20
|
+
form?: Record<string, unknown>;
|
|
21
|
+
formData?: Record<string, unknown>;
|
|
22
|
+
simple?: boolean;
|
|
23
|
+
resolveWithFullResponse?: boolean;
|
|
24
|
+
timeout?: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Create a request-promise-native compatible callable client.
|
|
28
|
+
* @param [logger] when given, verbose request/response logs are emitted
|
|
29
|
+
*/
|
|
30
|
+
export declare const createRequestClient: (logger?: {
|
|
31
|
+
verbose: (message: string, ...args: unknown[]) => void;
|
|
32
|
+
} | null) => (params?: RequestClientParams) => Promise<unknown>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A request-promise-native compatible HTTP client built on the global fetch.
|
|
3
|
+
*
|
|
4
|
+
* Keeps the option object and error shape used by the legacy `request`
|
|
5
|
+
* ecosystem so callers of HttpClient/RestClient see no interface change:
|
|
6
|
+
* - resolves with the response body (or the full response with
|
|
7
|
+
* `resolveWithFullResponse`)
|
|
8
|
+
* - rejects with an error carrying `.name` (`StatusCodeError`/`RequestError`),
|
|
9
|
+
* `.statusCode`, `.response` and `.request`
|
|
10
|
+
* - supports `url`, `method`, `headers`, `body`, `json`, `qs`, `form`,
|
|
11
|
+
* `formData`, `simple`, `resolveWithFullResponse` and `timeout`
|
|
12
|
+
*/
|
|
13
|
+
const MAX_BODY_LENGTH = parseInt(process.env.MAX_REQUEST_DEBUG_BODY, 10) || 3000;
|
|
14
|
+
const TOO_LONG_BODY = '____TLDR____';
|
|
15
|
+
let debugId = 0;
|
|
16
|
+
const toPlainHeaders = (headers = {}) => {
|
|
17
|
+
const result = {};
|
|
18
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
19
|
+
result[key] = String(value);
|
|
20
|
+
});
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
const buildQueryString = (qs) => {
|
|
24
|
+
if (qs === undefined || qs === null) {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
if (typeof qs === 'string') {
|
|
28
|
+
return qs.startsWith('?') ? qs : `?${qs}`;
|
|
29
|
+
}
|
|
30
|
+
return `?${new URLSearchParams(qs).toString()}`;
|
|
31
|
+
};
|
|
32
|
+
const buildBody = (params) => {
|
|
33
|
+
if (params.formData) {
|
|
34
|
+
const form = new FormData();
|
|
35
|
+
Object.entries(params.formData).forEach(([key, value]) => {
|
|
36
|
+
// FormData.append 运行时按 WebIDL 语义转换非字符串值,断言仅满足编译
|
|
37
|
+
form.append(key, value);
|
|
38
|
+
});
|
|
39
|
+
return { body: form, contentType: null };
|
|
40
|
+
}
|
|
41
|
+
if (params.form) {
|
|
42
|
+
return {
|
|
43
|
+
body: new URLSearchParams(params.form).toString(),
|
|
44
|
+
contentType: 'application/x-www-form-urlencoded'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//The legacy `json` option also accepts a value used as the JSON body
|
|
48
|
+
if (params.json !== undefined && params.json !== false && params.json !== true) {
|
|
49
|
+
return { body: JSON.stringify(params.json), contentType: 'application/json' };
|
|
50
|
+
}
|
|
51
|
+
if (params.json === true && params.body !== undefined) {
|
|
52
|
+
return { body: JSON.stringify(params.body), contentType: 'application/json' };
|
|
53
|
+
}
|
|
54
|
+
return { body: params.body, contentType: null };
|
|
55
|
+
};
|
|
56
|
+
const truncateBody = (body) => {
|
|
57
|
+
if (typeof body !== 'string') {
|
|
58
|
+
return body ? String(body) : '';
|
|
59
|
+
}
|
|
60
|
+
return body.length > MAX_BODY_LENGTH ? TOO_LONG_BODY : body;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Create a request-promise-native compatible callable client.
|
|
64
|
+
* @param [logger] when given, verbose request/response logs are emitted
|
|
65
|
+
*/
|
|
66
|
+
export const createRequestClient = (logger) => {
|
|
67
|
+
const request = (params = {}) => new Promise((resolve, reject) => {
|
|
68
|
+
const { url, method: rawMethod = 'GET', headers = {}, resolveWithFullResponse = false, simple = true, timeout = 0, qs } = params;
|
|
69
|
+
const method = String(rawMethod).toUpperCase();
|
|
70
|
+
const targetUrl = `${url}${buildQueryString(qs)}`;
|
|
71
|
+
const { body, contentType } = buildBody(params);
|
|
72
|
+
const requestHeaders = toPlainHeaders(headers);
|
|
73
|
+
if (contentType
|
|
74
|
+
&& !Object.keys(requestHeaders).some(key => key.toLowerCase() === 'content-type')) {
|
|
75
|
+
requestHeaders['Content-Type'] = contentType;
|
|
76
|
+
}
|
|
77
|
+
const abortController = new AbortController();
|
|
78
|
+
const timer = timeout > 0
|
|
79
|
+
? setTimeout(() => abortController.abort(new Error('Request timed out')), timeout)
|
|
80
|
+
: null;
|
|
81
|
+
const requestForDump = {
|
|
82
|
+
method,
|
|
83
|
+
uri: {
|
|
84
|
+
protocol: new URL(targetUrl).protocol,
|
|
85
|
+
href: targetUrl
|
|
86
|
+
},
|
|
87
|
+
headers: requestHeaders,
|
|
88
|
+
req: {},
|
|
89
|
+
_json: params.json !== undefined && params.json !== false
|
|
90
|
+
? true : body !== undefined,
|
|
91
|
+
formData: params.formData || null,
|
|
92
|
+
body: params.formData
|
|
93
|
+
? new URLSearchParams(params.formData).toString()
|
|
94
|
+
: body
|
|
95
|
+
};
|
|
96
|
+
const id = ++debugId;
|
|
97
|
+
if (logger) {
|
|
98
|
+
logger.verbose('[HTTP_REQUEST_%s] [%s %s] [REQ_HEADERS: %s] [REQ_BODY: %s]', id, method, targetUrl, JSON.stringify(requestHeaders), truncateBody(body));
|
|
99
|
+
}
|
|
100
|
+
fetch(targetUrl, {
|
|
101
|
+
method,
|
|
102
|
+
headers: requestHeaders,
|
|
103
|
+
body,
|
|
104
|
+
signal: abortController.signal,
|
|
105
|
+
redirect: 'follow'
|
|
106
|
+
}).then(async (response) => {
|
|
107
|
+
if (timer) {
|
|
108
|
+
clearTimeout(timer);
|
|
109
|
+
}
|
|
110
|
+
const rawBody = await response.text();
|
|
111
|
+
let parsedBody = rawBody;
|
|
112
|
+
if (params.json !== undefined && params.json !== false) {
|
|
113
|
+
try {
|
|
114
|
+
parsedBody = JSON.parse(rawBody);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
parsedBody = rawBody;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const responseForDump = {
|
|
121
|
+
statusCode: response.status,
|
|
122
|
+
statusMessage: response.statusText,
|
|
123
|
+
headers: toPlainHeaders(Object.fromEntries(response.headers.entries())),
|
|
124
|
+
body: parsedBody,
|
|
125
|
+
request: requestForDump
|
|
126
|
+
};
|
|
127
|
+
if (logger) {
|
|
128
|
+
logger.verbose('[HTTP_RESPONSE_%s] [%s %s] [%s] [RES_HEADERS: %s] [RES_BODY: %s]', id, method, targetUrl, response.status, JSON.stringify(responseForDump.headers), truncateBody(parsedBody));
|
|
129
|
+
}
|
|
130
|
+
if (response.status >= 400 && simple) {
|
|
131
|
+
const error = new Error(`Response status ${response.status}`);
|
|
132
|
+
error.name = 'StatusCodeError';
|
|
133
|
+
error.statusCode = response.status;
|
|
134
|
+
error.response = responseForDump;
|
|
135
|
+
error.request = requestForDump;
|
|
136
|
+
reject(error);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
resolve(resolveWithFullResponse ? responseForDump : parsedBody);
|
|
140
|
+
}).catch((err) => {
|
|
141
|
+
if (timer) {
|
|
142
|
+
clearTimeout(timer);
|
|
143
|
+
}
|
|
144
|
+
// 与原实现一致:非 Error 值时 err.message 为 undefined,new Error(undefined) 的语义保持不变
|
|
145
|
+
const error = new Error(err.message);
|
|
146
|
+
error.name = 'RequestError';
|
|
147
|
+
error.request = requestForDump;
|
|
148
|
+
reject(error);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
return request;
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=request_client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request_client.js","sourceRoot":"","sources":["../../src/utils/request_client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
type SmartQueryWhere = Record<string, Record<PropertyKey, unknown>>;
|
|
2
|
+
type SmartQueryCriteria = {
|
|
3
|
+
order?: unknown[];
|
|
4
|
+
where?: SmartQueryWhere;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* 自动根据 req.query 生成 sequelize 查询条件, 自动判断参数清单中是否有值
|
|
8
|
+
*/
|
|
9
|
+
export default class SmartQuery {
|
|
10
|
+
query: Record<string, unknown>;
|
|
11
|
+
/** WHERE 查询条件 */
|
|
12
|
+
where: SmartQueryWhere;
|
|
13
|
+
/**
|
|
14
|
+
* 排序列表
|
|
15
|
+
*/
|
|
16
|
+
order: unknown[];
|
|
17
|
+
constructor(query: Record<string, unknown>);
|
|
18
|
+
/**
|
|
19
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加全等查询条件
|
|
20
|
+
* @param paramName query 中的参数名称
|
|
21
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
22
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
23
|
+
*/
|
|
24
|
+
equal(paramName: string, fieldName?: string, defaultValue?: unknown): this;
|
|
25
|
+
/**
|
|
26
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 in 查询条件, 值可以为 `delimiter` 分割的字符串或者数组
|
|
27
|
+
* @param paramName query 中的参数名称
|
|
28
|
+
* @param [fieldName=paramName] 对应的数据库字段名称,默认与 paramName 一致
|
|
29
|
+
* @param [defaultValue=null] 当 query 中不包含 paramName 或为空时,使用该值
|
|
30
|
+
* @param [delimiter=,] 当值为字符串时的分隔符,默认为 ,
|
|
31
|
+
*/
|
|
32
|
+
in(paramName: string, fieldName?: string, defaultValue?: unknown, delimiter?: string): this;
|
|
33
|
+
/**
|
|
34
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 not in 查询条件, 值可以为 `delimiter` 分割的字符串或者数组
|
|
35
|
+
* @param paramName query 中的参数名称
|
|
36
|
+
* @param [fieldName=paramName] 对应的数据库字段名称,默认与 paramName 一致
|
|
37
|
+
* @param [defaultValue=null] 当 query 中不包含 paramName 或为空时,使用该值
|
|
38
|
+
* @param [delimiter=,] 当值为字符串时的分隔符,默认为 ,
|
|
39
|
+
*/
|
|
40
|
+
notIn(paramName: string, fieldName?: string, defaultValue?: unknown, delimiter?: string): this;
|
|
41
|
+
/**
|
|
42
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 LIKE 查询条件,并自动在值的头尾添加 %
|
|
43
|
+
* @param paramName query 中的参数名称
|
|
44
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
45
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
46
|
+
*/
|
|
47
|
+
like(paramName: string, fieldName?: string, defaultValue?: unknown): this;
|
|
48
|
+
/**
|
|
49
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 LIKE 查询条件,并自动在值的尾部添加 %
|
|
50
|
+
* @param paramName query 中的参数名称
|
|
51
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
52
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
53
|
+
*/
|
|
54
|
+
startsWith(paramName: string, fieldName?: string, defaultValue?: unknown): this;
|
|
55
|
+
/**
|
|
56
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 LIKE 查询条件,并自动在值的头部添加 %
|
|
57
|
+
* @param paramName query 中的参数名称
|
|
58
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
59
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
60
|
+
*/
|
|
61
|
+
endsWith(paramName: string, fieldName?: string, defaultValue?: unknown): this;
|
|
62
|
+
/**
|
|
63
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 >= 查询条件
|
|
64
|
+
* @param paramName query 中的参数名称
|
|
65
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
66
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
67
|
+
*/
|
|
68
|
+
gte(paramName: string, fieldName?: string, defaultValue?: unknown): this;
|
|
69
|
+
/**
|
|
70
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 <= 查询条件
|
|
71
|
+
* @param paramName query 中的参数名称
|
|
72
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
73
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
74
|
+
*/
|
|
75
|
+
lte(paramName: string, fieldName?: string, defaultValue?: unknown): this;
|
|
76
|
+
/**
|
|
77
|
+
* 当 query 中包含名为 minParamName 的属性时,为 fieldName 添加 >= 查询条件,
|
|
78
|
+
* 当 query 中包含名为 maxParamName 的属性时,为 fieldName 添加 <= 查询条件
|
|
79
|
+
* @param minParamName query 中的最小值参数名称
|
|
80
|
+
* @param maxParamName query 中的最大值参数名称
|
|
81
|
+
* @param fieldName 对应的数据库字段名称
|
|
82
|
+
* @param minDefault 当 query 中不包含 minParamName 或为空时,使用该值作为默认值
|
|
83
|
+
* @param maxDefault 当 query 中不包含 maxParamName 或为空时,使用该值作为默认值
|
|
84
|
+
*/
|
|
85
|
+
range(minParamName: string, maxParamName: string, fieldName: string, minDefault?: unknown, maxDefault?: unknown): this;
|
|
86
|
+
/**
|
|
87
|
+
* 当 query 中包含名为 minParamName 的属性时,为 fieldName 添加 >= 查询条件并将时分秒设为0格式化到 targetFormat ,
|
|
88
|
+
* 当 query 中包含名为 maxParamName 的属性时,为 fieldName 添加 <= 查询条件并将时分秒分别设为 23:59:59 后格式化到 targetFormat
|
|
89
|
+
* @param minParamName query 中的最小值参数名称
|
|
90
|
+
* @param maxParamName query 中的最大值参数名称
|
|
91
|
+
* @param fieldName 对应的数据库字段名称
|
|
92
|
+
* @param [minDefault=null] 当 query 中不包含 minParamName 或为空时,使用该值作为默认值
|
|
93
|
+
* @param [maxDefault=null] 当 query 中不包含 maxParamName 或为空时,使用该值作为默认值
|
|
94
|
+
* @param [sourceFormat='YYYY-MM-DD'] 原值时间格式
|
|
95
|
+
* @param [targetFormat='X'] 数据库时间格式
|
|
96
|
+
*/
|
|
97
|
+
dateRange(minParamName: string, maxParamName: string, fieldName: string, minDefault?: string | null, maxDefault?: string | null, sourceFormat?: string, targetFormat?: string): this;
|
|
98
|
+
/**
|
|
99
|
+
* 当 query 中包含名为 minParamName 的属性时,为 fieldName 添加 >= 查询条件并格式化到 targetFormat ,
|
|
100
|
+
* 当 query 中包含名为 maxParamName 的属性时,为 fieldName 添加 <= 查询条件并并格式化到 targetFormat
|
|
101
|
+
* @param minParamName query 中的最小值参数名称
|
|
102
|
+
* @param maxParamName query 中的最大值参数名称
|
|
103
|
+
* @param fieldName 对应的数据库字段名称
|
|
104
|
+
* @param [minDefault=null] 当 query 中不包含 minParamName 或为空时,使用该值作为默认值
|
|
105
|
+
* @param [maxDefault=null] 当 query 中不包含 maxParamName 或为空时,使用该值作为默认值
|
|
106
|
+
* @param [sourceFormat='YYYY-MM-DD HH:mm:ss'] 原值时间格式
|
|
107
|
+
* @param [targetFormat='X'] 数据库时间格式
|
|
108
|
+
*/
|
|
109
|
+
dateTimeRange(minParamName: string, maxParamName: string, fieldName: string, minDefault?: string | null, maxDefault?: string | null, sourceFormat?: string, targetFormat?: string): this;
|
|
110
|
+
/**
|
|
111
|
+
* 处理用户的排序请求
|
|
112
|
+
* @param [autoMapping=[]] 根据字段名自动排序,数组成员为字段名,每个字段名自动生成正反序,
|
|
113
|
+
* 如 `created_at` 生成 `created_at` 正序和 `-created_at` 倒序
|
|
114
|
+
* @param [manualMapping={}]
|
|
115
|
+
* @param [defaultOrder=null] 默认排序,当 query 中不包含 `paramName` 属性时使用。如不设置则为 `autoMapping` 的第一个字段的倒序
|
|
116
|
+
* @param [paramName='order'] 参数名称
|
|
117
|
+
*/
|
|
118
|
+
orderable(autoMapping?: string[], manualMapping?: Record<string, unknown>, defaultOrder?: unknown, paramName?: string): this;
|
|
119
|
+
/**
|
|
120
|
+
* 获取完整的有效查询参数
|
|
121
|
+
*/
|
|
122
|
+
getCriteria(): SmartQueryCriteria;
|
|
123
|
+
/**
|
|
124
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 in 或 not in 查询条件, 值可以为 `delimiter` 分割的字符串或者数组
|
|
125
|
+
* @protected
|
|
126
|
+
* @param paramName query 中的参数名称
|
|
127
|
+
* @param fieldName 对应的数据库字段名称
|
|
128
|
+
* @param [defaultValue=null] 当 query 中不包含 paramName 或为空时,使用该值
|
|
129
|
+
* @param [delimiter=,] 当值为字符串时的分隔符,默认为 ,
|
|
130
|
+
* @param [negation=false] 是否取反,为 true 时使用 $notIn
|
|
131
|
+
*/
|
|
132
|
+
applyIn(paramName: string, fieldName: string, defaultValue?: unknown, delimiter?: string, negation?: boolean): this;
|
|
133
|
+
/**
|
|
134
|
+
* 添加 where
|
|
135
|
+
*
|
|
136
|
+
* @protected
|
|
137
|
+
*/
|
|
138
|
+
applyWhere(filedName: string, predicate: string, value: unknown): void;
|
|
139
|
+
/**
|
|
140
|
+
* 判定指定名称的参数是否有效
|
|
141
|
+
*/
|
|
142
|
+
determineParam(paramName: string): boolean;
|
|
143
|
+
}
|
|
144
|
+
export {};
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import moment from 'moment-timezone';
|
|
2
|
+
import { Op } from 'sequelize';
|
|
3
|
+
import { InvalidArgumentException } from "../exceptions/index.js";
|
|
4
|
+
// Op 的值是 sequelize 的 symbol 运算符;where 的键可能是 string 或 symbol
|
|
5
|
+
const OPERATORS = {
|
|
6
|
+
$eq: Op.eq,
|
|
7
|
+
$like: Op.like,
|
|
8
|
+
$in: Op.in,
|
|
9
|
+
$notIn: Op.notIn,
|
|
10
|
+
$gte: Op.gte,
|
|
11
|
+
$lte: Op.lte
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* 自动根据 req.query 生成 sequelize 查询条件, 自动判断参数清单中是否有值
|
|
15
|
+
*/
|
|
16
|
+
export default class SmartQuery {
|
|
17
|
+
query;
|
|
18
|
+
/** WHERE 查询条件 */
|
|
19
|
+
where;
|
|
20
|
+
/**
|
|
21
|
+
* 排序列表
|
|
22
|
+
*/
|
|
23
|
+
order;
|
|
24
|
+
constructor(query) {
|
|
25
|
+
this.query = query;
|
|
26
|
+
this.where = {};
|
|
27
|
+
this.order = [];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加全等查询条件
|
|
31
|
+
* @param paramName query 中的参数名称
|
|
32
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
33
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
34
|
+
*/
|
|
35
|
+
equal(paramName, fieldName = paramName, defaultValue = null) {
|
|
36
|
+
const value = this.determineParam(paramName) ? this.query[paramName] : defaultValue;
|
|
37
|
+
if (value != null) {
|
|
38
|
+
this.applyWhere(fieldName, '$eq', value);
|
|
39
|
+
}
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 in 查询条件, 值可以为 `delimiter` 分割的字符串或者数组
|
|
44
|
+
* @param paramName query 中的参数名称
|
|
45
|
+
* @param [fieldName=paramName] 对应的数据库字段名称,默认与 paramName 一致
|
|
46
|
+
* @param [defaultValue=null] 当 query 中不包含 paramName 或为空时,使用该值
|
|
47
|
+
* @param [delimiter=,] 当值为字符串时的分隔符,默认为 ,
|
|
48
|
+
*/
|
|
49
|
+
in(paramName, fieldName = paramName, defaultValue = null, delimiter = ',') {
|
|
50
|
+
return this.applyIn(paramName, fieldName, defaultValue, delimiter, false);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 not in 查询条件, 值可以为 `delimiter` 分割的字符串或者数组
|
|
54
|
+
* @param paramName query 中的参数名称
|
|
55
|
+
* @param [fieldName=paramName] 对应的数据库字段名称,默认与 paramName 一致
|
|
56
|
+
* @param [defaultValue=null] 当 query 中不包含 paramName 或为空时,使用该值
|
|
57
|
+
* @param [delimiter=,] 当值为字符串时的分隔符,默认为 ,
|
|
58
|
+
*/
|
|
59
|
+
notIn(paramName, fieldName = paramName, defaultValue = null, delimiter = ',') {
|
|
60
|
+
return this.applyIn(paramName, fieldName, defaultValue, delimiter, true);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 LIKE 查询条件,并自动在值的头尾添加 %
|
|
64
|
+
* @param paramName query 中的参数名称
|
|
65
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
66
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
67
|
+
*/
|
|
68
|
+
like(paramName, fieldName = paramName, defaultValue = null) {
|
|
69
|
+
const value = this.determineParam(paramName) ? this.query[paramName] : defaultValue;
|
|
70
|
+
if (value != null) {
|
|
71
|
+
this.applyWhere(fieldName, '$like', `%${value}%`);
|
|
72
|
+
}
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 LIKE 查询条件,并自动在值的尾部添加 %
|
|
77
|
+
* @param paramName query 中的参数名称
|
|
78
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
79
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
80
|
+
*/
|
|
81
|
+
startsWith(paramName, fieldName = paramName, defaultValue = null) {
|
|
82
|
+
const value = this.determineParam(paramName) ? this.query[paramName] : defaultValue;
|
|
83
|
+
if (value != null) {
|
|
84
|
+
this.applyWhere(fieldName, '$like', `${value}%`);
|
|
85
|
+
}
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 LIKE 查询条件,并自动在值的头部添加 %
|
|
90
|
+
* @param paramName query 中的参数名称
|
|
91
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
92
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
93
|
+
*/
|
|
94
|
+
endsWith(paramName, fieldName = paramName, defaultValue = null) {
|
|
95
|
+
const value = this.determineParam(paramName) ? this.query[paramName] : defaultValue;
|
|
96
|
+
if (value != null) {
|
|
97
|
+
this.applyWhere(fieldName, '$like', `%${value}`);
|
|
98
|
+
}
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 >= 查询条件
|
|
103
|
+
* @param paramName query 中的参数名称
|
|
104
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
105
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
106
|
+
*/
|
|
107
|
+
gte(paramName, fieldName = paramName, defaultValue = null) {
|
|
108
|
+
const value = this.determineParam(paramName) ? this.query[paramName] : defaultValue;
|
|
109
|
+
if (value != null) {
|
|
110
|
+
this.applyWhere(fieldName, '$gte', value);
|
|
111
|
+
}
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 <= 查询条件
|
|
116
|
+
* @param paramName query 中的参数名称
|
|
117
|
+
* @param fieldName 对应的数据库字段名称,默认与 paramName 一致
|
|
118
|
+
* @param defaultValue 当 query 中不包含 paramName 或为空时,使用该值
|
|
119
|
+
*/
|
|
120
|
+
lte(paramName, fieldName = paramName, defaultValue = null) {
|
|
121
|
+
const value = this.determineParam(paramName) ? this.query[paramName] : defaultValue;
|
|
122
|
+
if (value != null) {
|
|
123
|
+
this.applyWhere(fieldName, '$lte', value);
|
|
124
|
+
}
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 当 query 中包含名为 minParamName 的属性时,为 fieldName 添加 >= 查询条件,
|
|
129
|
+
* 当 query 中包含名为 maxParamName 的属性时,为 fieldName 添加 <= 查询条件
|
|
130
|
+
* @param minParamName query 中的最小值参数名称
|
|
131
|
+
* @param maxParamName query 中的最大值参数名称
|
|
132
|
+
* @param fieldName 对应的数据库字段名称
|
|
133
|
+
* @param minDefault 当 query 中不包含 minParamName 或为空时,使用该值作为默认值
|
|
134
|
+
* @param maxDefault 当 query 中不包含 maxParamName 或为空时,使用该值作为默认值
|
|
135
|
+
*/
|
|
136
|
+
range(minParamName, maxParamName, fieldName, minDefault = null, maxDefault = null) {
|
|
137
|
+
const min = this.determineParam(minParamName) ? this.query[minParamName] : minDefault;
|
|
138
|
+
const max = this.determineParam(maxParamName) ? this.query[maxParamName] : maxDefault;
|
|
139
|
+
if (min != null) {
|
|
140
|
+
this.applyWhere(fieldName, '$gte', min);
|
|
141
|
+
}
|
|
142
|
+
if (max != null) {
|
|
143
|
+
this.applyWhere(fieldName, '$lte', max);
|
|
144
|
+
}
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 当 query 中包含名为 minParamName 的属性时,为 fieldName 添加 >= 查询条件并将时分秒设为0格式化到 targetFormat ,
|
|
149
|
+
* 当 query 中包含名为 maxParamName 的属性时,为 fieldName 添加 <= 查询条件并将时分秒分别设为 23:59:59 后格式化到 targetFormat
|
|
150
|
+
* @param minParamName query 中的最小值参数名称
|
|
151
|
+
* @param maxParamName query 中的最大值参数名称
|
|
152
|
+
* @param fieldName 对应的数据库字段名称
|
|
153
|
+
* @param [minDefault=null] 当 query 中不包含 minParamName 或为空时,使用该值作为默认值
|
|
154
|
+
* @param [maxDefault=null] 当 query 中不包含 maxParamName 或为空时,使用该值作为默认值
|
|
155
|
+
* @param [sourceFormat='YYYY-MM-DD'] 原值时间格式
|
|
156
|
+
* @param [targetFormat='X'] 数据库时间格式
|
|
157
|
+
*/
|
|
158
|
+
dateRange(minParamName, maxParamName, fieldName, minDefault = null, maxDefault = null, sourceFormat = 'YYYY-MM-DD', targetFormat = 'X') {
|
|
159
|
+
const minParam = this.determineParam(minParamName)
|
|
160
|
+
? this.query[minParamName]
|
|
161
|
+
: null;
|
|
162
|
+
// minDefault 为 null 时依赖 moment(null) 的 invalid 语义,不做可选值替换
|
|
163
|
+
const min = minParam != null && moment(minParam, sourceFormat).isValid()
|
|
164
|
+
? moment(minParam, sourceFormat)
|
|
165
|
+
: moment(minDefault, sourceFormat);
|
|
166
|
+
const maxParam = this.determineParam(maxParamName) ? this.query[maxParamName] : null;
|
|
167
|
+
const max = maxParam != null && moment(maxParam, sourceFormat).isValid()
|
|
168
|
+
? moment(maxParam, sourceFormat)
|
|
169
|
+
: moment(maxDefault, sourceFormat);
|
|
170
|
+
if (min.isValid()) {
|
|
171
|
+
this.applyWhere(fieldName, '$gte', min.hours(0).minutes(0).seconds(0).format(targetFormat));
|
|
172
|
+
}
|
|
173
|
+
if (max.isValid()) {
|
|
174
|
+
this.applyWhere(fieldName, '$lte', max.hours(23).minutes(59).seconds(59).format(targetFormat));
|
|
175
|
+
}
|
|
176
|
+
return this;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* 当 query 中包含名为 minParamName 的属性时,为 fieldName 添加 >= 查询条件并格式化到 targetFormat ,
|
|
180
|
+
* 当 query 中包含名为 maxParamName 的属性时,为 fieldName 添加 <= 查询条件并并格式化到 targetFormat
|
|
181
|
+
* @param minParamName query 中的最小值参数名称
|
|
182
|
+
* @param maxParamName query 中的最大值参数名称
|
|
183
|
+
* @param fieldName 对应的数据库字段名称
|
|
184
|
+
* @param [minDefault=null] 当 query 中不包含 minParamName 或为空时,使用该值作为默认值
|
|
185
|
+
* @param [maxDefault=null] 当 query 中不包含 maxParamName 或为空时,使用该值作为默认值
|
|
186
|
+
* @param [sourceFormat='YYYY-MM-DD HH:mm:ss'] 原值时间格式
|
|
187
|
+
* @param [targetFormat='X'] 数据库时间格式
|
|
188
|
+
*/
|
|
189
|
+
dateTimeRange(minParamName, maxParamName, fieldName, minDefault = null, maxDefault = null, sourceFormat = 'YYYY-MM-DD HH:mm:ss', targetFormat = 'X') {
|
|
190
|
+
const minParam = this.determineParam(minParamName)
|
|
191
|
+
? this.query[minParamName]
|
|
192
|
+
: null;
|
|
193
|
+
// minDefault 为 null 时依赖 moment(null) 的 invalid 语义,不做可选值替换
|
|
194
|
+
const min = minParam != null && moment(minParam, sourceFormat).isValid()
|
|
195
|
+
? moment(minParam, sourceFormat)
|
|
196
|
+
: moment(minDefault, sourceFormat);
|
|
197
|
+
const maxParam = this.determineParam(maxParamName) ? this.query[maxParamName] : null;
|
|
198
|
+
const max = maxParam != null && moment(maxParam, sourceFormat).isValid()
|
|
199
|
+
? moment(maxParam, sourceFormat)
|
|
200
|
+
: moment(maxDefault, sourceFormat);
|
|
201
|
+
if (min.isValid()) {
|
|
202
|
+
this.applyWhere(fieldName, '$gte', min.format(targetFormat));
|
|
203
|
+
}
|
|
204
|
+
if (max.isValid()) {
|
|
205
|
+
this.applyWhere(fieldName, '$lte', max.format(targetFormat));
|
|
206
|
+
}
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* 处理用户的排序请求
|
|
211
|
+
* @param [autoMapping=[]] 根据字段名自动排序,数组成员为字段名,每个字段名自动生成正反序,
|
|
212
|
+
* 如 `created_at` 生成 `created_at` 正序和 `-created_at` 倒序
|
|
213
|
+
* @param [manualMapping={}]
|
|
214
|
+
* @param [defaultOrder=null] 默认排序,当 query 中不包含 `paramName` 属性时使用。如不设置则为 `autoMapping` 的第一个字段的倒序
|
|
215
|
+
* @param [paramName='order'] 参数名称
|
|
216
|
+
*/
|
|
217
|
+
orderable(autoMapping = [], manualMapping = {}, defaultOrder = null, paramName = 'order') {
|
|
218
|
+
const ordersMapping = {};
|
|
219
|
+
let conventionOrder = defaultOrder;
|
|
220
|
+
if (autoMapping instanceof Array) {
|
|
221
|
+
autoMapping.forEach((field) => {
|
|
222
|
+
ordersMapping[`-${field}`] = [field, 'DESC'];
|
|
223
|
+
ordersMapping[field] = [field, 'ASC'];
|
|
224
|
+
});
|
|
225
|
+
if (conventionOrder === null) {
|
|
226
|
+
conventionOrder = [autoMapping[0], 'DESC'];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
Object.assign(ordersMapping, manualMapping);
|
|
230
|
+
const order = this.determineParam(paramName) && Object.keys(ordersMapping).includes(this.query[paramName])
|
|
231
|
+
? ordersMapping[this.query[paramName]] : conventionOrder;
|
|
232
|
+
if (order != null) {
|
|
233
|
+
this.order = [order];
|
|
234
|
+
}
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* 获取完整的有效查询参数
|
|
239
|
+
*/
|
|
240
|
+
getCriteria() {
|
|
241
|
+
const criteria = {};
|
|
242
|
+
if (this.order instanceof Array && this.order.length > 0) {
|
|
243
|
+
criteria.order = this.order;
|
|
244
|
+
}
|
|
245
|
+
if (Object.keys(this.where).length > 0) {
|
|
246
|
+
criteria.where = this.where;
|
|
247
|
+
}
|
|
248
|
+
return criteria;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* 当 query 中包含名为 paramName 的属性时,为 fieldName 添加 in 或 not in 查询条件, 值可以为 `delimiter` 分割的字符串或者数组
|
|
252
|
+
* @protected
|
|
253
|
+
* @param paramName query 中的参数名称
|
|
254
|
+
* @param fieldName 对应的数据库字段名称
|
|
255
|
+
* @param [defaultValue=null] 当 query 中不包含 paramName 或为空时,使用该值
|
|
256
|
+
* @param [delimiter=,] 当值为字符串时的分隔符,默认为 ,
|
|
257
|
+
* @param [negation=false] 是否取反,为 true 时使用 $notIn
|
|
258
|
+
*/
|
|
259
|
+
applyIn(paramName, fieldName, defaultValue = null, delimiter = ',', negation = false) {
|
|
260
|
+
let value = this.determineParam(paramName) ? this.query[paramName] : defaultValue;
|
|
261
|
+
if (value === null) {
|
|
262
|
+
return this;
|
|
263
|
+
}
|
|
264
|
+
if (typeof value === 'number') {
|
|
265
|
+
value = String(value);
|
|
266
|
+
}
|
|
267
|
+
if (typeof value === 'string') {
|
|
268
|
+
value = value.split(delimiter);
|
|
269
|
+
}
|
|
270
|
+
else if (value instanceof Array === false) {
|
|
271
|
+
throw new InvalidArgumentException(`Value for contains must be typeof string or array, but \`${typeof value}\` given`);
|
|
272
|
+
}
|
|
273
|
+
this.applyWhere(fieldName, negation ? '$notIn' : '$in', value);
|
|
274
|
+
return this;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* 添加 where
|
|
278
|
+
*
|
|
279
|
+
* @protected
|
|
280
|
+
*/
|
|
281
|
+
applyWhere(filedName, predicate, value) {
|
|
282
|
+
if (!Object.keys(this.where).includes(filedName)) {
|
|
283
|
+
this.where[filedName] = {};
|
|
284
|
+
}
|
|
285
|
+
this.where[filedName][OPERATORS[predicate] || predicate] = value;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* 判定指定名称的参数是否有效
|
|
289
|
+
*/
|
|
290
|
+
determineParam(paramName) {
|
|
291
|
+
if (!Object.keys(this.query).includes(paramName)) {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
const value = this.query[paramName];
|
|
295
|
+
if (value === null) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
if (typeof value === 'string') {
|
|
299
|
+
return value.trim() !== '';
|
|
300
|
+
}
|
|
301
|
+
if (value instanceof Array) {
|
|
302
|
+
return value.length > 0;
|
|
303
|
+
}
|
|
304
|
+
if (value instanceof Object) {
|
|
305
|
+
return Object.keys(value).length > 0;
|
|
306
|
+
}
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=smart_query.js.map
|