typespeed 0.0.1 → 2.0.2
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/LICENSE +21 -0
- package/README.md +34 -0
- package/dist/core.decorator.d.ts +18 -0
- package/dist/core.decorator.js +185 -0
- package/dist/core.decorator.js.map +1 -0
- package/dist/database.decorator.d.ts +24 -0
- package/dist/database.decorator.js +335 -0
- package/dist/database.decorator.js.map +1 -0
- package/dist/default/express-server.class.d.ts +15 -0
- package/dist/default/express-server.class.js +148 -0
- package/dist/default/express-server.class.js.map +1 -0
- package/dist/default/log-default.class.d.ts +6 -0
- package/dist/default/log-default.class.js +32 -0
- package/dist/default/log-default.class.js.map +1 -0
- package/dist/default/node-cache.class.d.ts +13 -0
- package/dist/default/node-cache.class.js +51 -0
- package/dist/default/node-cache.class.js.map +1 -0
- package/dist/default/pages/404.html +226 -0
- package/dist/default/pages/500.html +713 -0
- package/dist/default/read-write-db.class.d.ts +10 -0
- package/dist/default/read-write-db.class.js +66 -0
- package/dist/default/read-write-db.class.js.map +1 -0
- package/dist/default/redis.class.d.ts +5 -0
- package/dist/default/redis.class.js +32 -0
- package/dist/default/redis.class.js.map +1 -0
- package/dist/factory/cache-factory.class.d.ts +7 -0
- package/dist/factory/cache-factory.class.js +6 -0
- package/dist/factory/cache-factory.class.js.map +1 -0
- package/dist/factory/data-source-factory.class.d.ts +4 -0
- package/dist/factory/data-source-factory.class.js +6 -0
- package/dist/factory/data-source-factory.class.js.map +1 -0
- package/dist/factory/log-factory.class.d.ts +4 -0
- package/dist/factory/log-factory.class.js +6 -0
- package/dist/factory/log-factory.class.js.map +1 -0
- package/dist/factory/server-factory.class.d.ts +6 -0
- package/dist/factory/server-factory.class.js +9 -0
- package/dist/factory/server-factory.class.js.map +1 -0
- package/dist/route.decorator.d.ts +8 -0
- package/dist/route.decorator.js +87 -0
- package/dist/route.decorator.js.map +1 -0
- package/dist/typespeed.d.ts +12 -0
- package/dist/typespeed.js +39 -0
- package/dist/typespeed.js.map +1 -0
- package/package.json +39 -6
- package/src/core.decorator.ts +183 -0
- package/src/database.decorator.ts +342 -0
- package/src/default/express-server.class.ts +133 -0
- package/src/default/log-default.class.ts +19 -0
- package/src/default/node-cache.class.ts +39 -0
- package/src/default/pages/404.html +226 -0
- package/src/default/pages/500.html +713 -0
- package/src/default/read-write-db.class.ts +53 -0
- package/src/default/redis.class.ts +18 -0
- package/src/factory/cache-factory.class.ts +7 -0
- package/src/factory/data-source-factory.class.ts +4 -0
- package/src/factory/log-factory.class.ts +4 -0
- package/src/factory/server-factory.class.ts +6 -0
- package/src/route.decorator.ts +82 -0
- package/src/typespeed.ts +15 -0
- package/test/nodemon.json +6 -0
- package/test/package.json +18 -0
- package/test/src/aop-test.class.ts +29 -0
- package/test/src/config-development.json +15 -0
- package/test/src/config-production.json +15 -0
- package/test/src/config.json +46 -0
- package/test/src/custom-log.class.ts +26 -0
- package/test/src/entities/user-dto.class.ts +3 -0
- package/test/src/first-page.class.ts +46 -0
- package/test/src/main.ts +17 -0
- package/test/src/second-page.class.ts +43 -0
- package/test/src/test-database.class.ts +85 -0
- package/test/src/test-log.class.ts +9 -0
- package/test/src/test-orm.class.ts +74 -0
- package/test/src/user-model.class.ts +45 -0
- package/test/src/views/index.html +1 -0
- package/test/src/views/upload.html +14 -0
- package/test/static/favicon.ico +0 -0
- package/test/static/k.jpg +0 -0
- package/test/tsconfig.json +20 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { ResultSetHeader } from 'mysql2';
|
|
2
|
+
import { log, getBean } from './core.decorator';
|
|
3
|
+
import CacheFactory from './factory/cache-factory.class';
|
|
4
|
+
import DataSourceFactory from './factory/data-source-factory.class';
|
|
5
|
+
|
|
6
|
+
const paramMetadataKey = Symbol('param');
|
|
7
|
+
const resultTypeMap = new Map<string, object>();
|
|
8
|
+
const cacheDefindMap = new Map<string, number>();
|
|
9
|
+
const tableVersionMap = new Map<string, number>();
|
|
10
|
+
let cacheBean: CacheFactory;
|
|
11
|
+
|
|
12
|
+
function insert(sql: string) {
|
|
13
|
+
return (target, propertyKey: string, descriptor: PropertyDescriptor) => {
|
|
14
|
+
descriptor.value = async (...args: any[]) => {
|
|
15
|
+
const result: ResultSetHeader = await queryForExecute(sql, args, target, propertyKey);
|
|
16
|
+
if (cacheBean && result.affectedRows > 0) {
|
|
17
|
+
const [tableName, tableVersion] = getTableAndVersion("insert", sql);
|
|
18
|
+
tableVersionMap.set(tableName, tableVersion + 1);
|
|
19
|
+
}
|
|
20
|
+
return result.insertId;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function update(sql: string) {
|
|
26
|
+
return (target, propertyKey: string, descriptor: PropertyDescriptor) => {
|
|
27
|
+
descriptor.value = async (...args: any[]) => {
|
|
28
|
+
const result: ResultSetHeader = await queryForExecute(sql, args, target, propertyKey);
|
|
29
|
+
if (cacheBean && result.affectedRows > 0) {
|
|
30
|
+
const [tableName, tableVersion] = getTableAndVersion("update", sql);
|
|
31
|
+
tableVersionMap.set(tableName, tableVersion + 1);
|
|
32
|
+
}
|
|
33
|
+
return result.affectedRows;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function remove(sql: string) {
|
|
39
|
+
return (target, propertyKey: string, descriptor: PropertyDescriptor) => {
|
|
40
|
+
descriptor.value = async (...args: any[]) => {
|
|
41
|
+
const result: ResultSetHeader = await queryForExecute(sql, args, target, propertyKey);
|
|
42
|
+
if (cacheBean && result.affectedRows > 0) {
|
|
43
|
+
const [tableName, tableVersion] = getTableAndVersion("delete", sql);
|
|
44
|
+
tableVersionMap.set(tableName, tableVersion + 1);
|
|
45
|
+
}
|
|
46
|
+
return result.affectedRows;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function select(sql: string) {
|
|
52
|
+
return (target, propertyKey: string, descriptor: PropertyDescriptor) => {
|
|
53
|
+
descriptor.value = async (...args: any[]) => {
|
|
54
|
+
const [newSql, sqlValues] = convertSQLParams(sql, target, propertyKey, args);
|
|
55
|
+
const resultType = resultTypeMap.get([target.constructor.name, propertyKey].toString());
|
|
56
|
+
if (cacheBean && cacheDefindMap.has([target.constructor.name, propertyKey].toString())) {
|
|
57
|
+
const [tableName, tableVersion] = getTableAndVersion("select", newSql);
|
|
58
|
+
const cacheKey = JSON.stringify([tableName, tableVersion, newSql, sqlValues]);
|
|
59
|
+
if (cacheBean.get(cacheKey)) {
|
|
60
|
+
return cacheBean.get(cacheKey);
|
|
61
|
+
} else {
|
|
62
|
+
const rows = await actionQuery(newSql, sqlValues, resultType);
|
|
63
|
+
cacheBean.set(cacheKey, rows, cacheDefindMap.get([target.constructor.name, propertyKey].toString()));
|
|
64
|
+
return rows;
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
return await actionQuery(newSql, sqlValues, resultType);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function resultType(dataClass) {
|
|
74
|
+
return function (target, propertyKey: string) {
|
|
75
|
+
resultTypeMap.set([target.constructor.name, propertyKey].toString(), new dataClass());
|
|
76
|
+
//never return
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function param(name: string) {
|
|
81
|
+
return function (target: any, propertyKey: string | symbol, parameterIndex: number) {
|
|
82
|
+
const existingParameters: [string, number][] = Reflect.getOwnMetadata(paramMetadataKey, target, propertyKey) || [];
|
|
83
|
+
existingParameters.push([name, parameterIndex]);
|
|
84
|
+
Reflect.defineMetadata(paramMetadataKey, existingParameters, target, propertyKey);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function queryForExecute(sql: string, args: any[], target, propertyKey: string): Promise<ResultSetHeader> {
|
|
89
|
+
const [newSql, sqlValues] = convertSQLParams(sql, target, propertyKey, args);
|
|
90
|
+
return actionExecute(newSql, sqlValues);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function actionExecute(newSql, sqlValues): Promise<ResultSetHeader> {
|
|
94
|
+
const writeConnection = await getBean(DataSourceFactory).writeConnection();
|
|
95
|
+
const [result] = await writeConnection.query(newSql, sqlValues);
|
|
96
|
+
return <ResultSetHeader>result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function actionQuery(newSql, sqlValues, dataClassType?) {
|
|
100
|
+
const readConnection = await getBean(DataSourceFactory).readConnection();
|
|
101
|
+
const [rows] = await readConnection.query(newSql, sqlValues);
|
|
102
|
+
if (rows === null || Object.keys(rows).length === 0 || !dataClassType) {
|
|
103
|
+
return rows;
|
|
104
|
+
}
|
|
105
|
+
const records = [];
|
|
106
|
+
for (const rowIndex in rows) {
|
|
107
|
+
const entity = new dataClassType();
|
|
108
|
+
Object.getOwnPropertyNames(entity).forEach((propertyRow) => {
|
|
109
|
+
if (rows[rowIndex].hasOwnProperty(propertyRow)) {
|
|
110
|
+
Object.defineProperty(entity, propertyRow, Object.getOwnPropertyDescriptor(rows[rowIndex], propertyRow));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
records.push(entity);
|
|
114
|
+
}
|
|
115
|
+
return records;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function convertSQLParams(decoratorSQL: string, target: any, propertyKey: string, args: any[]): [string, any[]] {
|
|
119
|
+
const queryValues = [];
|
|
120
|
+
if (args.length > 0) {
|
|
121
|
+
let argsVal;
|
|
122
|
+
if (typeof args[0] === 'object') {
|
|
123
|
+
argsVal = new Map(Object.getOwnPropertyNames(args[0]).map((valName) => [valName, args[0][valName]]));
|
|
124
|
+
} else {
|
|
125
|
+
const existingParameters: [string, number][] = Reflect.getOwnMetadata(paramMetadataKey, target, propertyKey,);
|
|
126
|
+
argsVal = new Map(existingParameters.map(([argName, argIdx]) => [argName, args[argIdx]]));
|
|
127
|
+
}
|
|
128
|
+
const regExp = /#{(\w+)}/;
|
|
129
|
+
let match;
|
|
130
|
+
while (match = regExp.exec(decoratorSQL)) {
|
|
131
|
+
const [replaceTag, matchName] = match;
|
|
132
|
+
decoratorSQL = decoratorSQL.replace(new RegExp(replaceTag, 'g'), '?');
|
|
133
|
+
queryValues.push(argsVal.get(matchName));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return [decoratorSQL, queryValues];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function cache(ttl: number) {
|
|
140
|
+
return function (target: any, propertyKey: string) {
|
|
141
|
+
cacheDefindMap.set([target.constructor.name, propertyKey].toString(), ttl);
|
|
142
|
+
if (cacheBean == null) {
|
|
143
|
+
const cacheFactory = getBean(CacheFactory);
|
|
144
|
+
if (cacheFactory || cacheFactory["factory"]) {
|
|
145
|
+
cacheBean = cacheFactory["factory"];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getTableAndVersion(name: string, sql: string): [string, number] {
|
|
152
|
+
const regExpMap = {
|
|
153
|
+
insert: /insert\sinto\s+([\w`\'\"]+)/i,
|
|
154
|
+
update: /update\s+([\w`\'\"]+)/i,
|
|
155
|
+
delete: /delete\sfrom\s+([\w`\'\"]+)/i,
|
|
156
|
+
select: /\s+from\s+([\w`\'\"]+)/i
|
|
157
|
+
}
|
|
158
|
+
const macths = sql.match(regExpMap[name]);
|
|
159
|
+
if (macths && macths.length > 1) {
|
|
160
|
+
const tableName = macths[1].replace(/[`\'\"]/g, "");
|
|
161
|
+
const tableVersion = tableVersionMap.get(tableName) || 1;
|
|
162
|
+
tableVersionMap.set(tableName, tableVersion);
|
|
163
|
+
log(tableVersionMap);
|
|
164
|
+
return [tableName, tableVersion];
|
|
165
|
+
} else {
|
|
166
|
+
throw new Error("can not find table name");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class Model {
|
|
172
|
+
|
|
173
|
+
public page = null;
|
|
174
|
+
private table: string;
|
|
175
|
+
|
|
176
|
+
constructor(table?: string) {
|
|
177
|
+
if (table) this.table = table;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async findAll<T>(conditions: object | string, sort: string | object = '', fields: string | [string] = '*', limit?: number | object): Promise<T[]> {
|
|
181
|
+
const { sql, values } = this.where(conditions);
|
|
182
|
+
if (typeof fields !== 'string') {
|
|
183
|
+
fields = fields.join(", ");
|
|
184
|
+
}
|
|
185
|
+
if (typeof sort !== 'string') {
|
|
186
|
+
sort = Object.keys(sort).map(s => {
|
|
187
|
+
return s + (sort[s] === 1 ? " ASC" : " DESC");
|
|
188
|
+
}).join(", ");
|
|
189
|
+
}
|
|
190
|
+
let newSql = 'SELECT ' + fields + ' FROM ' + this.table + ' WHERE ' + sql + " ORDER BY " + sort;
|
|
191
|
+
if (typeof limit === 'number') {
|
|
192
|
+
newSql += ' LIMIT ' + limit
|
|
193
|
+
} else if (typeof limit === 'object') {
|
|
194
|
+
const total = await actionQuery('SELECT COUNT(*) AS M_COUNTER FROM ' + this.table + ' WHERE ' + sql, values);
|
|
195
|
+
if (total === undefined || total[0]['M_COUNTER'] === 0) {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
if (limit['pageSize'] !== undefined && limit['pageSize'] < total[0]['M_COUNTER']) {
|
|
199
|
+
const pager = this.pager(limit["page"] || 1, total[0]['M_COUNTER'], limit["pageSize"] || 10, limit["scope"] || 10);
|
|
200
|
+
newSql += ' LIMIT ' + pager['offset'] + ',' + pager['limit'];
|
|
201
|
+
this.page = pager;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return <T[]>await actionQuery(newSql, values);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async create(rows): Promise<number> {
|
|
208
|
+
let newSql = "";
|
|
209
|
+
let values = [];
|
|
210
|
+
if (!Array.isArray(rows)) {
|
|
211
|
+
rows = [rows];
|
|
212
|
+
}
|
|
213
|
+
const firstRow = rows[0];
|
|
214
|
+
newSql += 'INSERT INTO ' + this.table + ' (' + Object.keys(firstRow).map((field) => '`' + field + '`').join(', ') + ') VALUES';
|
|
215
|
+
rows.forEach((row) => {
|
|
216
|
+
const valueRow = [];
|
|
217
|
+
Object.keys(row).map((field) => {
|
|
218
|
+
values.push(row[field]);
|
|
219
|
+
valueRow.push('?');
|
|
220
|
+
});
|
|
221
|
+
newSql += '(' + valueRow.map((value) => '?').join(', ') + ')' + (rows.indexOf(row) === rows.length - 1 ? '' : ',');
|
|
222
|
+
});
|
|
223
|
+
const result: ResultSetHeader = await actionExecute(newSql, values);
|
|
224
|
+
return result.insertId;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async find<T>(conditions, sort, fields = '*'): Promise<T> {
|
|
228
|
+
const result = await this.findAll(conditions, sort, fields, 1);
|
|
229
|
+
return result.length > 0 ? <T>result[0] : null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async update(conditions, fieldToValues): Promise<number> {
|
|
233
|
+
const { sql, values } = this.where(conditions);
|
|
234
|
+
const newSql = 'UPDATE ' + this.table + ' SET ' + Object.keys(fieldToValues).map((field) => { return '`' + field + '` = ? ' }).join(', ') + ' WHERE ' + sql;
|
|
235
|
+
const result: ResultSetHeader = await actionExecute(newSql, Object.values(fieldToValues).concat(values));
|
|
236
|
+
return result.affectedRows;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async delete(conditions): Promise<number> {
|
|
240
|
+
const { sql, values } = this.where(conditions);
|
|
241
|
+
const newSql = 'DELETE FROM ' + this.table + ' WHERE ' + sql;
|
|
242
|
+
const result: ResultSetHeader = await actionExecute(newSql, values);
|
|
243
|
+
return result.affectedRows;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async findCount(conditions): Promise<number> {
|
|
247
|
+
const { sql, values } = this.where(conditions);
|
|
248
|
+
const newSql = 'SELECT COUNT(*) AS M_COUNTER FROM ' + this.table + ' WHERE ' + sql;
|
|
249
|
+
const result = await actionQuery(newSql, values);
|
|
250
|
+
return result[0]['M_COUNTER'] || 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async incr(conditions, field, optval = 1): Promise<number> {
|
|
254
|
+
const { sql, values } = this.where(conditions);
|
|
255
|
+
const newSql = 'UPDATE ' + this.table + ' SET `' + field + '` = `' + field + '` + ? WHERE ' + sql;
|
|
256
|
+
values.unshift(optval); // increase at the top
|
|
257
|
+
const result: ResultSetHeader = await actionExecute(newSql, values);
|
|
258
|
+
return result.affectedRows;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async decr(conditions, field, optval = 1): Promise<number> {
|
|
262
|
+
return await this.incr(conditions, field, -optval);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
pager(page, total, pageSize = 10, scope = 10) {
|
|
266
|
+
this.page = null
|
|
267
|
+
if (total === undefined) throw new Error('Pager total would not be undefined')
|
|
268
|
+
if (total > pageSize) {
|
|
269
|
+
let totalPage = Math.ceil(total / pageSize)
|
|
270
|
+
page = Math.min(Math.max(page, 1), total)
|
|
271
|
+
this.page = {
|
|
272
|
+
'total': total,
|
|
273
|
+
'pageSize': pageSize,
|
|
274
|
+
'totalPage': totalPage,
|
|
275
|
+
'firstPage': 1,
|
|
276
|
+
'prevPage': ((1 == page) ? 1 : (page - 1)),
|
|
277
|
+
'nextPage': ((page == totalPage) ? totalPage : (page + 1)),
|
|
278
|
+
'lastPage': totalPage,
|
|
279
|
+
'currentPage': page,
|
|
280
|
+
'allPages': [],
|
|
281
|
+
'offset': (page - 1) * pageSize,
|
|
282
|
+
'limit': pageSize
|
|
283
|
+
}
|
|
284
|
+
if (totalPage <= scope) {
|
|
285
|
+
this.page.allPages = this.range(1, totalPage)
|
|
286
|
+
} else if (page <= scope / 2) {
|
|
287
|
+
this.page.allPages = this.range(1, scope)
|
|
288
|
+
} else if (page <= totalPage - scope / 2) {
|
|
289
|
+
let right = page + (scope / 2)
|
|
290
|
+
this.page.allPages = this.range(right - scope + 1, right)
|
|
291
|
+
} else {
|
|
292
|
+
this.page.allPages = this.range(totalPage - scope + 1, totalPage)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return this.page
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private where(conditions: object | string): { sql: string, values: any[] } {
|
|
299
|
+
const result = { sql: '', values: [] };
|
|
300
|
+
if (typeof conditions === 'object') {
|
|
301
|
+
Object.keys(conditions).map((field) => {
|
|
302
|
+
if (result["sql"].length > 0) {
|
|
303
|
+
result["sql"] += " AND "
|
|
304
|
+
}
|
|
305
|
+
if (typeof conditions[field] === 'object') {
|
|
306
|
+
if (field === '$or') {
|
|
307
|
+
let orSql = "";
|
|
308
|
+
conditions[field].map((item) => {
|
|
309
|
+
const { sql, values } = this.where(item);
|
|
310
|
+
orSql += (orSql.length > 0 ? " OR " : "") + `(${sql})`;
|
|
311
|
+
result["values"] = result["values"].concat(values);
|
|
312
|
+
});
|
|
313
|
+
result["sql"] += `(${orSql})`;
|
|
314
|
+
} else {
|
|
315
|
+
const operatorTemplate = { $lt: "<", $lte: "<=", $gt: ">", $gte: ">=", $ne: "!=", $like: "LIKE" };
|
|
316
|
+
let firstCondition: boolean = Object.keys(conditions[field]).length > 1;
|
|
317
|
+
Object.keys(conditions[field]).map((operator) => {
|
|
318
|
+
if (operatorTemplate[operator]) {
|
|
319
|
+
const operatorValue = operatorTemplate[operator];
|
|
320
|
+
result["sql"] += ` ${field} ${operatorValue} ? ` + (firstCondition ? " AND " : "");
|
|
321
|
+
result["values"].push(conditions[field][operator]);
|
|
322
|
+
firstCondition = false;
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
result["sql"] += ` ${field} = ? `;
|
|
328
|
+
result["values"].push(conditions[field]);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
} else {
|
|
332
|
+
result["sql"] = conditions;
|
|
333
|
+
}
|
|
334
|
+
return result
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
private range(start, end) {
|
|
338
|
+
return [...Array(end - start + 1).keys()].map(i => i + start);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export { insert, update, remove, select, param, resultType, cache, Model };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as express from "express";
|
|
3
|
+
import * as consolidate from "consolidate";
|
|
4
|
+
import * as serveFavicon from "serve-favicon";
|
|
5
|
+
import * as compression from "compression";
|
|
6
|
+
import * as cookieParser from "cookie-parser";
|
|
7
|
+
import * as expressSession from "express-session";
|
|
8
|
+
import * as connectRedis from "connect-redis";
|
|
9
|
+
import ServerFactory from "../factory/server-factory.class";
|
|
10
|
+
import { setRouter } from "../route.decorator";
|
|
11
|
+
import { bean, log, value, error, autoware } from "../core.decorator";
|
|
12
|
+
import Redis from "./redis.class";
|
|
13
|
+
|
|
14
|
+
export default class ExpressServer extends ServerFactory {
|
|
15
|
+
|
|
16
|
+
@value("view")
|
|
17
|
+
public view: string;
|
|
18
|
+
|
|
19
|
+
@value("static")
|
|
20
|
+
private static: string;
|
|
21
|
+
|
|
22
|
+
@value("favicon")
|
|
23
|
+
private favicon: string;
|
|
24
|
+
|
|
25
|
+
@value("compression")
|
|
26
|
+
private compression: object;
|
|
27
|
+
|
|
28
|
+
@value("cookie")
|
|
29
|
+
private cookieConfig: object;
|
|
30
|
+
|
|
31
|
+
@value("session")
|
|
32
|
+
private session: object;
|
|
33
|
+
|
|
34
|
+
@value("redis")
|
|
35
|
+
private redisConfig: object;
|
|
36
|
+
|
|
37
|
+
@autoware
|
|
38
|
+
private redisClient: Redis;
|
|
39
|
+
|
|
40
|
+
@bean
|
|
41
|
+
public getSever(): ServerFactory {
|
|
42
|
+
const server = new ExpressServer();
|
|
43
|
+
server.app = express();
|
|
44
|
+
return server;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public setMiddleware(middleware: any) {
|
|
48
|
+
this.middlewareList.push(middleware);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public start(port: number) {
|
|
52
|
+
this.middlewareList.forEach(middleware => {
|
|
53
|
+
this.app.use(middleware);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.setDefaultMiddleware();
|
|
57
|
+
this.app.listen(port, () => {
|
|
58
|
+
log("server start at port: " + port);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private setDefaultMiddleware() {
|
|
63
|
+
this.app.use(express.urlencoded({ extended: true }));
|
|
64
|
+
this.app.use(express.json());
|
|
65
|
+
if (this.view) {
|
|
66
|
+
const viewConfig = this.view;
|
|
67
|
+
this.app.engine(viewConfig["suffix"], consolidate[viewConfig["engine"]]);
|
|
68
|
+
this.app.set('view engine', viewConfig["suffix"]);
|
|
69
|
+
this.app.set('views', process.cwd() + viewConfig["path"]);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (this.session) {
|
|
73
|
+
const sessionConfig = this.session;
|
|
74
|
+
if (sessionConfig["trust proxy"] === 1) {
|
|
75
|
+
this.app.set('trust proxy', 1);
|
|
76
|
+
}
|
|
77
|
+
if (this.redisConfig) {
|
|
78
|
+
const RedisStore = connectRedis(expressSession);
|
|
79
|
+
sessionConfig["store"] = new RedisStore({ client: this.redisClient });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.app.use(expressSession(sessionConfig));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (this.static) {
|
|
86
|
+
const staticPath = process.cwd() + this.static;
|
|
87
|
+
this.app.use(express.static(staticPath))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (this.favicon) {
|
|
91
|
+
const faviconPath = process.cwd() + this.favicon;
|
|
92
|
+
this.app.use(serveFavicon(faviconPath));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (this.compression) {
|
|
96
|
+
this.app.use(compression(this.compression));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (this.cookieConfig) {
|
|
100
|
+
this.app.use(cookieParser(this.cookieConfig["secret"] || undefined, this.cookieConfig["options"] || {}));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setRouter(this.app);
|
|
104
|
+
|
|
105
|
+
const errorPageDir = __dirname + "/pages";
|
|
106
|
+
this.app.use((req, res) => {
|
|
107
|
+
error("404 not found, for page: " + req.url);
|
|
108
|
+
res.status(404);
|
|
109
|
+
if (req.accepts('html')) {
|
|
110
|
+
res.type('html').send(fs.readFileSync(errorPageDir + "/404.html", "utf-8"));
|
|
111
|
+
} else if (req.accepts('json')) {
|
|
112
|
+
res.json({ error: 'Not found' });
|
|
113
|
+
} else {
|
|
114
|
+
res.type('txt').send('Not found');
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
this.app.use((err, req, res, next) => {
|
|
119
|
+
if (!err) {
|
|
120
|
+
next();
|
|
121
|
+
}
|
|
122
|
+
error(err);
|
|
123
|
+
res.status(err.status || 500);
|
|
124
|
+
if (req.accepts('html')) {
|
|
125
|
+
res.type('html').send(fs.readFileSync(errorPageDir + "/500.html", "utf-8"));
|
|
126
|
+
} else if (req.accepts('json')) {
|
|
127
|
+
res.json({ error: 'Internal Server Error' });
|
|
128
|
+
} else {
|
|
129
|
+
res.type('txt').send('Internal Server Error');
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { bean } from "../core.decorator";
|
|
2
|
+
import LogFactory from "../factory/log-factory.class";
|
|
3
|
+
|
|
4
|
+
export default class LogDefault extends LogFactory {
|
|
5
|
+
|
|
6
|
+
@bean
|
|
7
|
+
createLog(): LogFactory {
|
|
8
|
+
return new LogDefault();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public log(message?: any, ...optionalParams: any[]): void {
|
|
12
|
+
console.log(message, ...optionalParams);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public error(message?: any, ...optionalParams: any[]) : void{
|
|
16
|
+
console.error(message, ...optionalParams);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import CacheFactory from "../factory/cache-factory.class";
|
|
2
|
+
import * as cache from "node-cache";
|
|
3
|
+
import { value, bean } from "../core.decorator";
|
|
4
|
+
|
|
5
|
+
export default class NodeCache extends CacheFactory {
|
|
6
|
+
private NodeCache: any;
|
|
7
|
+
private nodeCacheOptions;
|
|
8
|
+
|
|
9
|
+
@value("cache")
|
|
10
|
+
private config : object;
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
this.nodeCacheOptions = this.config || { stdTTL: 3600 };
|
|
15
|
+
this.NodeCache = new cache();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@bean
|
|
19
|
+
public getNodeCache(): CacheFactory {
|
|
20
|
+
return new NodeCache();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public get(key: string) {
|
|
24
|
+
return this.NodeCache.get(key);
|
|
25
|
+
}
|
|
26
|
+
public set(key: string, value: any, expire?: number): void {
|
|
27
|
+
this.NodeCache.set(key, value, expire || this.nodeCacheOptions["stdTTL"]);
|
|
28
|
+
}
|
|
29
|
+
public del(key: string): void {
|
|
30
|
+
this.NodeCache.del(key);
|
|
31
|
+
}
|
|
32
|
+
public has(key: string): boolean {
|
|
33
|
+
return this.NodeCache.has(key);
|
|
34
|
+
}
|
|
35
|
+
public flush(): void {
|
|
36
|
+
this.NodeCache.flushAll();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|