oak-db 3.3.10 → 3.3.12
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/lib/MySQL/connector.d.ts +15 -15
- package/lib/MySQL/connector.js +77 -77
- package/lib/MySQL/store.d.ts +30 -4
- package/lib/MySQL/store.js +125 -3
- package/lib/MySQL/translator.d.ts +114 -107
- package/lib/MySQL/translator.js +1207 -969
- package/lib/MySQL/types/Configuration.d.ts +12 -12
- package/lib/MySQL/types/Configuration.js +2 -2
- package/lib/PostgreSQL/connector.d.ts +31 -0
- package/lib/PostgreSQL/connector.js +157 -0
- package/lib/PostgreSQL/store.d.ts +38 -0
- package/lib/PostgreSQL/store.js +329 -0
- package/lib/PostgreSQL/translator.d.ts +83 -0
- package/lib/PostgreSQL/translator.js +1770 -0
- package/lib/PostgreSQL/types/Configuration.d.ts +13 -0
- package/lib/PostgreSQL/types/Configuration.js +2 -0
- package/lib/index.d.ts +4 -2
- package/lib/index.js +5 -4
- package/lib/sqlTranslator.d.ts +68 -55
- package/lib/sqlTranslator.js +72 -39
- package/lib/types/Translator.d.ts +3 -3
- package/lib/types/Translator.js +2 -2
- package/lib/types/configuration.d.ts +7 -0
- package/lib/types/configuration.js +2 -0
- package/lib/types/dbStore.d.ts +8 -0
- package/lib/types/dbStore.js +3 -0
- package/package.json +6 -5
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type PostgreSQLConfiguration = {
|
|
2
|
+
host: string;
|
|
3
|
+
user: string;
|
|
4
|
+
password: string;
|
|
5
|
+
database: string;
|
|
6
|
+
port?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
idleTimeoutMillis?: number;
|
|
9
|
+
connectionTimeoutMillis?: number;
|
|
10
|
+
};
|
|
11
|
+
export type Configuration = {
|
|
12
|
+
postgresql: PostgreSQLConfiguration;
|
|
13
|
+
};
|
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
export * from './MySQL/store';
|
|
2
|
-
export { MySqlSelectOption, MysqlOperateOption } from './MySQL/translator';
|
|
1
|
+
export * from './MySQL/store';
|
|
2
|
+
export { MySqlSelectOption, MysqlOperateOption } from './MySQL/translator';
|
|
3
|
+
export * from './PostgreSQL/store';
|
|
4
|
+
export { PostgreSQLSelectOption, PostgreSQLOperateOption } from './PostgreSQL/translator';
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
tslib_1.__exportStar(require("./MySQL/store"), exports);
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./MySQL/store"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./PostgreSQL/store"), exports);
|
package/lib/sqlTranslator.d.ts
CHANGED
|
@@ -1,55 +1,68 @@
|
|
|
1
|
-
import { EntityDict, OperateOption, Q_FullTextValue, Ref, RefOrExpression, SelectOption, StorageSchema } from "oak-domain/lib/types";
|
|
2
|
-
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
|
3
|
-
import { DataType } from "oak-domain/lib/types/schema/DataTypes";
|
|
4
|
-
import { CreateEntityOption } from './types/Translator';
|
|
5
|
-
export interface SqlSelectOption extends SelectOption {
|
|
6
|
-
}
|
|
7
|
-
export interface SqlOperateOption extends OperateOption {
|
|
8
|
-
}
|
|
9
|
-
export declare abstract class SqlTranslator<ED extends EntityDict & BaseEntityDict> {
|
|
10
|
-
readonly schema: StorageSchema<ED>;
|
|
11
|
-
constructor(schema: StorageSchema<ED>);
|
|
12
|
-
private makeFullSchema;
|
|
13
|
-
protected abstract getDefaultSelectFilter<OP extends SqlSelectOption>(alias: string, option?: OP): string;
|
|
14
|
-
protected abstract translateAttrProjection(dataType: DataType, alias: string, attr: string): string;
|
|
15
|
-
protected abstract translateObjectProjection(projection: Record<string, any>, alias: string, attr: string, prefix: string): string;
|
|
16
|
-
protected abstract translateAttrValue(dataType: DataType | Ref, value: any): string;
|
|
17
|
-
protected abstract translateFullTextSearch<T extends keyof ED>(value: Q_FullTextValue, entity: T, alias: string): string;
|
|
18
|
-
abstract translateCreateEntity<T extends keyof ED>(entity: T, option: CreateEntityOption): string[];
|
|
19
|
-
protected abstract translateObjectPredicate(predicate: Record<string, any>, alias: string, attr: string): string;
|
|
20
|
-
protected abstract populateSelectStmt<T extends keyof ED, OP extends SqlSelectOption>(projectionText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, groupByText?: string, indexFrom?: number, count?: number, option?: OP, selection?: ED[T]['Selection'], aggregation?: ED[T]['Aggregation']): string;
|
|
21
|
-
protected abstract populateUpdateStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
|
|
22
|
-
protected abstract populateRemoveStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
|
|
23
|
-
protected abstract translateExpression<T extends keyof ED>(entity: T, alias: string, expression: RefOrExpression<keyof ED[T]['OpSchema']>, refDict: Record<string, [string, keyof ED]>): string;
|
|
24
|
-
|
|
25
|
-
translateInsert<T extends keyof ED>(entity: T, data: ED[T]['CreateMulti']['data']): string;
|
|
26
|
-
/**
|
|
27
|
-
* analyze the join relations in projection/query/sort
|
|
28
|
-
* 所有的层次关系都当成left join处理,如果有内表为空的情况,请手动处理
|
|
29
|
-
* {
|
|
30
|
-
* b: {
|
|
31
|
-
* name: {
|
|
32
|
-
* $exists: false,
|
|
33
|
-
* }
|
|
34
|
-
* }
|
|
35
|
-
* }
|
|
36
|
-
* 这样的query会把内表为空的行也返回
|
|
37
|
-
* @param param0
|
|
38
|
-
*/
|
|
39
|
-
private analyzeJoin;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
import { EntityDict, OperateOption, Q_FullTextValue, Ref, RefOrExpression, SelectOption, StorageSchema } from "oak-domain/lib/types";
|
|
2
|
+
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
|
3
|
+
import { DataType } from "oak-domain/lib/types/schema/DataTypes";
|
|
4
|
+
import { CreateEntityOption } from './types/Translator';
|
|
5
|
+
export interface SqlSelectOption extends SelectOption {
|
|
6
|
+
}
|
|
7
|
+
export interface SqlOperateOption extends OperateOption {
|
|
8
|
+
}
|
|
9
|
+
export declare abstract class SqlTranslator<ED extends EntityDict & BaseEntityDict> {
|
|
10
|
+
readonly schema: StorageSchema<ED>;
|
|
11
|
+
constructor(schema: StorageSchema<ED>);
|
|
12
|
+
private makeFullSchema;
|
|
13
|
+
protected abstract getDefaultSelectFilter<OP extends SqlSelectOption>(alias: string, option?: OP): string;
|
|
14
|
+
protected abstract translateAttrProjection(dataType: DataType, alias: string, attr: string): string;
|
|
15
|
+
protected abstract translateObjectProjection(projection: Record<string, any>, alias: string, attr: string, prefix: string): string;
|
|
16
|
+
protected abstract translateAttrValue(dataType: DataType | Ref, value: any): string;
|
|
17
|
+
protected abstract translateFullTextSearch<T extends keyof ED>(value: Q_FullTextValue, entity: T, alias: string): string;
|
|
18
|
+
abstract translateCreateEntity<T extends keyof ED>(entity: T, option: CreateEntityOption): string[];
|
|
19
|
+
protected abstract translateObjectPredicate(predicate: Record<string, any>, alias: string, attr: string): string;
|
|
20
|
+
protected abstract populateSelectStmt<T extends keyof ED, OP extends SqlSelectOption>(projectionText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, groupByText?: string, indexFrom?: number, count?: number, option?: OP, selection?: ED[T]['Selection'], aggregation?: ED[T]['Aggregation']): string;
|
|
21
|
+
protected abstract populateUpdateStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
|
|
22
|
+
protected abstract populateRemoveStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
|
|
23
|
+
protected abstract translateExpression<T extends keyof ED>(entity: T, alias: string, expression: RefOrExpression<keyof ED[T]['OpSchema']>, refDict: Record<string, [string, keyof ED]>): string;
|
|
24
|
+
protected getStorageName<T extends keyof ED>(entity: T): string;
|
|
25
|
+
translateInsert<T extends keyof ED>(entity: T, data: ED[T]['CreateMulti']['data']): string;
|
|
26
|
+
/**
|
|
27
|
+
* analyze the join relations in projection/query/sort
|
|
28
|
+
* 所有的层次关系都当成left join处理,如果有内表为空的情况,请手动处理
|
|
29
|
+
* {
|
|
30
|
+
* b: {
|
|
31
|
+
* name: {
|
|
32
|
+
* $exists: false,
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* 这样的query会把内表为空的行也返回
|
|
37
|
+
* @param param0
|
|
38
|
+
*/
|
|
39
|
+
private analyzeJoin;
|
|
40
|
+
/**
|
|
41
|
+
* 对like模式中的特殊字符进行转义
|
|
42
|
+
* 例如 % 和 _,以防止被当成通配符处理
|
|
43
|
+
* @param pattern like模式字符串
|
|
44
|
+
* @returns 转义后的字符串
|
|
45
|
+
*/
|
|
46
|
+
escapeLikePattern(pattern: string): string;
|
|
47
|
+
private translateComparison;
|
|
48
|
+
private translateEvaluation;
|
|
49
|
+
protected translatePredicate(predicate: string, value: any, type?: DataType | Ref): string;
|
|
50
|
+
protected translateFilter<T extends keyof ED, OP extends SqlSelectOption>(entity: T, filter: ED[T]['Selection']['filter'], aliasDict: Record<string, string>, filterRefAlias: Record<string, [string, keyof ED]>, initialNumber: number, option?: OP): {
|
|
51
|
+
stmt: string;
|
|
52
|
+
currentNumber: number;
|
|
53
|
+
};
|
|
54
|
+
private translateSorter;
|
|
55
|
+
private translateProjection;
|
|
56
|
+
private translateSelectInner;
|
|
57
|
+
translateSelect<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: ED[T]['Selection'], option?: OP): string;
|
|
58
|
+
translateWhere<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: ED[T]['Selection'], option?: OP): string;
|
|
59
|
+
translateAggregate<T extends keyof ED, OP extends SqlSelectOption>(entity: T, aggregation: ED[T]['Aggregation'], option?: OP): string;
|
|
60
|
+
translateCount<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, option?: OP): string;
|
|
61
|
+
translateRemove<T extends keyof ED, OP extends SqlOperateOption>(entity: T, operation: ED[T]['Remove'], option?: OP): string;
|
|
62
|
+
translateUpdate<T extends keyof ED, OP extends SqlOperateOption>(entity: T, operation: ED[T]['Update'], option?: OP): string;
|
|
63
|
+
translateDestroyEntity(entity: string, truncate?: boolean): string;
|
|
64
|
+
escapeStringValue(value: string): string;
|
|
65
|
+
/**比较两段sql是否完全一致,这里是把所有的空格去掉了 */
|
|
66
|
+
compareSql(sql1: string, sql2: string): boolean;
|
|
67
|
+
quoteIdentifier(name: string): string;
|
|
68
|
+
}
|
package/lib/sqlTranslator.js
CHANGED
|
@@ -21,7 +21,7 @@ class SqlTranslator {
|
|
|
21
21
|
const { attributes, indexes } = schema[entity];
|
|
22
22
|
// 增加默认的属性
|
|
23
23
|
(0, lodash_1.assign)(attributes, {
|
|
24
|
-
|
|
24
|
+
[types_1.PrimaryKeyAttribute]: {
|
|
25
25
|
type: 'char',
|
|
26
26
|
params: {
|
|
27
27
|
length: 36,
|
|
@@ -69,7 +69,7 @@ class SqlTranslator {
|
|
|
69
69
|
name: types_1.DeleteAtAttribute,
|
|
70
70
|
}],
|
|
71
71
|
}, {
|
|
72
|
-
name: `${entity}
|
|
72
|
+
name: `${entity}_trigger_uuid_auto_create`,
|
|
73
73
|
attributes: [{
|
|
74
74
|
name: types_1.TriggerUuidAttribute,
|
|
75
75
|
}]
|
|
@@ -137,6 +137,16 @@ class SqlTranslator {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
if (indexes) {
|
|
140
|
+
for (const index of indexes) {
|
|
141
|
+
const { attributes, config } = index;
|
|
142
|
+
if (!config?.type || config.type === 'btree') {
|
|
143
|
+
if (!attributes.find((ele) => ele.name === types_1.DeleteAtAttribute)) {
|
|
144
|
+
attributes.push({
|
|
145
|
+
name: types_1.DeleteAtAttribute,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
140
150
|
indexes.push(...intrinsticIndexes);
|
|
141
151
|
}
|
|
142
152
|
else {
|
|
@@ -154,14 +164,14 @@ class SqlTranslator {
|
|
|
154
164
|
translateInsert(entity, data) {
|
|
155
165
|
const { schema } = this;
|
|
156
166
|
const { attributes, storageName = entity } = schema[entity];
|
|
157
|
-
let sql = `insert into
|
|
167
|
+
let sql = `insert into ${this.quoteIdentifier(storageName)}(`;
|
|
158
168
|
/**
|
|
159
169
|
* 这里的attrs要用所有行的union集合
|
|
160
170
|
*/
|
|
161
171
|
const dataFull = data.reduce((prev, cur) => Object.assign({}, cur, prev), {});
|
|
162
172
|
const attrs = Object.keys(dataFull).filter(ele => attributes.hasOwnProperty(ele));
|
|
163
173
|
attrs.forEach((attr, idx) => {
|
|
164
|
-
sql += `
|
|
174
|
+
sql += ` ${this.quoteIdentifier(attr)}`;
|
|
165
175
|
if (idx < attrs.length - 1) {
|
|
166
176
|
sql += ',';
|
|
167
177
|
}
|
|
@@ -209,7 +219,7 @@ class SqlTranslator {
|
|
|
209
219
|
const projectionRefAlias = {};
|
|
210
220
|
const filterRefAlias = {};
|
|
211
221
|
const alias = `${entity}_${number++}`;
|
|
212
|
-
let from = `
|
|
222
|
+
let from = ` ${this.quoteIdentifier(this.getStorageName(entity))} ${this.quoteIdentifier(alias)} `;
|
|
213
223
|
const aliasDict = {
|
|
214
224
|
'./': alias,
|
|
215
225
|
};
|
|
@@ -243,7 +253,7 @@ class SqlTranslator {
|
|
|
243
253
|
(0, lodash_1.assign)(aliasDict, {
|
|
244
254
|
[pathAttr]: alias2,
|
|
245
255
|
});
|
|
246
|
-
from += ` left join
|
|
256
|
+
from += ` left join ${this.quoteIdentifier(this.getStorageName(rel))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier(op + 'Id')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')}`;
|
|
247
257
|
}
|
|
248
258
|
else {
|
|
249
259
|
alias2 = aliasDict[pathAttr];
|
|
@@ -263,7 +273,7 @@ class SqlTranslator {
|
|
|
263
273
|
(0, lodash_1.assign)(aliasDict, {
|
|
264
274
|
[pathAttr]: alias2,
|
|
265
275
|
});
|
|
266
|
-
from += ` left join
|
|
276
|
+
from += ` left join ${this.quoteIdentifier(this.getStorageName(op))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entityId')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')} and ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entity')} = '${op}'`;
|
|
267
277
|
}
|
|
268
278
|
else {
|
|
269
279
|
alias2 = aliasDict[pathAttr];
|
|
@@ -307,7 +317,7 @@ class SqlTranslator {
|
|
|
307
317
|
(0, lodash_1.assign)(aliasDict, {
|
|
308
318
|
[pathAttr]: alias2,
|
|
309
319
|
});
|
|
310
|
-
from += ` left join
|
|
320
|
+
from += ` left join ${this.quoteIdentifier(this.getStorageName(rel))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr + 'Id')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')}`;
|
|
311
321
|
}
|
|
312
322
|
else {
|
|
313
323
|
alias2 = aliasDict[pathAttr];
|
|
@@ -327,7 +337,7 @@ class SqlTranslator {
|
|
|
327
337
|
(0, lodash_1.assign)(aliasDict, {
|
|
328
338
|
[pathAttr]: alias2,
|
|
329
339
|
});
|
|
330
|
-
from += ` left join
|
|
340
|
+
from += ` left join ${this.quoteIdentifier(this.getStorageName(attr))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entityId')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')} and ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entity')} = '${attr}'`;
|
|
331
341
|
}
|
|
332
342
|
else {
|
|
333
343
|
alias2 = aliasDict[pathAttr];
|
|
@@ -365,7 +375,7 @@ class SqlTranslator {
|
|
|
365
375
|
(0, lodash_1.assign)(aliasDict, {
|
|
366
376
|
[pathAttr]: alias2,
|
|
367
377
|
});
|
|
368
|
-
from += ` left join
|
|
378
|
+
from += ` left join ${this.quoteIdentifier(this.getStorageName(rel))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr + 'Id')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')}`;
|
|
369
379
|
}
|
|
370
380
|
else {
|
|
371
381
|
alias2 = aliasDict[pathAttr];
|
|
@@ -385,7 +395,7 @@ class SqlTranslator {
|
|
|
385
395
|
(0, lodash_1.assign)(aliasDict, {
|
|
386
396
|
[pathAttr]: alias2,
|
|
387
397
|
});
|
|
388
|
-
from += ` left join
|
|
398
|
+
from += ` left join ${this.quoteIdentifier(this.getStorageName(attr))} ${this.quoteIdentifier(alias2)} on ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entityId')} = ${this.quoteIdentifier(alias2)}.${this.quoteIdentifier('id')} and ${this.quoteIdentifier(alias)}.${this.quoteIdentifier('entity')} = '${attr}'`;
|
|
389
399
|
}
|
|
390
400
|
else {
|
|
391
401
|
alias2 = aliasDict[pathAttr];
|
|
@@ -426,6 +436,15 @@ class SqlTranslator {
|
|
|
426
436
|
currentNumber: number,
|
|
427
437
|
};
|
|
428
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* 对like模式中的特殊字符进行转义
|
|
441
|
+
* 例如 % 和 _,以防止被当成通配符处理
|
|
442
|
+
* @param pattern like模式字符串
|
|
443
|
+
* @returns 转义后的字符串
|
|
444
|
+
*/
|
|
445
|
+
escapeLikePattern(pattern) {
|
|
446
|
+
return pattern.replace(/[%_]/g, (match) => `\\${match}`);
|
|
447
|
+
}
|
|
429
448
|
translateComparison(attr, value, type) {
|
|
430
449
|
const SQL_OP = {
|
|
431
450
|
$gt: '>',
|
|
@@ -445,16 +464,19 @@ class SqlTranslator {
|
|
|
445
464
|
}
|
|
446
465
|
switch (attr) {
|
|
447
466
|
case '$startsWith': {
|
|
448
|
-
|
|
467
|
+
const escaped = this.escapeLikePattern(value);
|
|
468
|
+
return ` LIKE '${escaped}%'`;
|
|
449
469
|
}
|
|
450
470
|
case '$endsWith': {
|
|
451
|
-
|
|
471
|
+
const escaped = this.escapeLikePattern(value);
|
|
472
|
+
return ` LIKE '%${escaped}'`;
|
|
452
473
|
}
|
|
453
474
|
case '$includes': {
|
|
454
|
-
|
|
475
|
+
const escaped = this.escapeLikePattern(value);
|
|
476
|
+
return ` LIKE '%${escaped}%'`;
|
|
455
477
|
}
|
|
456
478
|
default: {
|
|
457
|
-
throw new Error(`
|
|
479
|
+
throw new Error(`unrecognized comparison operator ${attr}`);
|
|
458
480
|
}
|
|
459
481
|
}
|
|
460
482
|
}
|
|
@@ -499,7 +521,7 @@ class SqlTranslator {
|
|
|
499
521
|
};
|
|
500
522
|
const values = value.map((v) => {
|
|
501
523
|
if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
|
|
502
|
-
return
|
|
524
|
+
return this.escapeStringValue(String(v));
|
|
503
525
|
}
|
|
504
526
|
else {
|
|
505
527
|
return `${v}`;
|
|
@@ -516,7 +538,7 @@ class SqlTranslator {
|
|
|
516
538
|
else if (predicate === '$between') {
|
|
517
539
|
const values = value.map((v) => {
|
|
518
540
|
if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
|
|
519
|
-
return
|
|
541
|
+
return this.escapeStringValue(String(v));
|
|
520
542
|
}
|
|
521
543
|
else {
|
|
522
544
|
return `${v}`;
|
|
@@ -626,7 +648,7 @@ class SqlTranslator {
|
|
|
626
648
|
filter: filter2[attr]
|
|
627
649
|
}, currentNumber, filterRefAlias, option);
|
|
628
650
|
currentNumber = ct2;
|
|
629
|
-
whereText += `(${
|
|
651
|
+
whereText += `(${this.quoteIdentifier(alias)}.${this.quoteIdentifier('id')} ${predicate} (${stmt}))`;
|
|
630
652
|
}
|
|
631
653
|
else {
|
|
632
654
|
/**
|
|
@@ -682,15 +704,18 @@ class SqlTranslator {
|
|
|
682
704
|
whereText += `(${this.translateObjectPredicate(filter2[attr], alias, attr)})`;
|
|
683
705
|
}
|
|
684
706
|
else {
|
|
707
|
+
if (!filter2[attr]) {
|
|
708
|
+
throw new Error(`属性${attr}的查询条件不能为null或undefined`);
|
|
709
|
+
}
|
|
685
710
|
(0, assert_1.default)(Object.keys(filter2[attr]).length === 1);
|
|
686
711
|
const predicate = Object.keys(filter2[attr])[0];
|
|
687
712
|
(0, assert_1.default)(predicate.startsWith('$'));
|
|
688
713
|
// 对属性上的谓词处理
|
|
689
|
-
whereText += ` (
|
|
714
|
+
whereText += ` (${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)} ${this.translatePredicate(predicate, filter2[attr][predicate], type2)})`;
|
|
690
715
|
}
|
|
691
716
|
}
|
|
692
717
|
else {
|
|
693
|
-
whereText += ` (
|
|
718
|
+
whereText += ` (${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)} = ${this.translateAttrValue(type2, filter2[attr])})`;
|
|
694
719
|
}
|
|
695
720
|
}
|
|
696
721
|
}
|
|
@@ -716,7 +741,7 @@ class SqlTranslator {
|
|
|
716
741
|
return this.translateExpression(entity2, alias, sortAttr[attr], {});
|
|
717
742
|
}
|
|
718
743
|
else if (sortAttr[attr] === 1) {
|
|
719
|
-
return
|
|
744
|
+
return `${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)}`;
|
|
720
745
|
}
|
|
721
746
|
else {
|
|
722
747
|
const rel = (0, relation_1.judgeRelation)(this.schema, entity2, attr);
|
|
@@ -765,12 +790,12 @@ class SqlTranslator {
|
|
|
765
790
|
projText += ` ${exprText}`;
|
|
766
791
|
}
|
|
767
792
|
else {
|
|
768
|
-
projText += ` ${exprText} as
|
|
793
|
+
projText += ` ${exprText} as ${this.quoteIdentifier(prefix2 + attr)}`;
|
|
769
794
|
if (!as) {
|
|
770
|
-
as =
|
|
795
|
+
as = this.quoteIdentifier(prefix2 + attr);
|
|
771
796
|
}
|
|
772
797
|
else {
|
|
773
|
-
as += `,
|
|
798
|
+
as += `, ${this.quoteIdentifier(prefix2 + attr)}`;
|
|
774
799
|
}
|
|
775
800
|
}
|
|
776
801
|
}
|
|
@@ -789,12 +814,12 @@ class SqlTranslator {
|
|
|
789
814
|
projText += ` ${this.translateAttrProjection(type, alias, attr)}`;
|
|
790
815
|
}
|
|
791
816
|
else {
|
|
792
|
-
projText += ` ${this.translateAttrProjection(type, alias, attr)} as
|
|
817
|
+
projText += ` ${this.translateAttrProjection(type, alias, attr)} as ${this.quoteIdentifier(prefix2 + attr)}`;
|
|
793
818
|
if (!as) {
|
|
794
|
-
as =
|
|
819
|
+
as = this.quoteIdentifier(prefix2 + attr);
|
|
795
820
|
}
|
|
796
821
|
else {
|
|
797
|
-
as += `,
|
|
822
|
+
as += `, ${this.quoteIdentifier(prefix2 + attr)}`;
|
|
798
823
|
}
|
|
799
824
|
}
|
|
800
825
|
}
|
|
@@ -810,12 +835,12 @@ class SqlTranslator {
|
|
|
810
835
|
projText += ` ${this.translateAttrProjection(type, alias, attr)}`;
|
|
811
836
|
}
|
|
812
837
|
else {
|
|
813
|
-
projText += ` ${this.translateAttrProjection(type, alias, attr)} as
|
|
838
|
+
projText += ` ${this.translateAttrProjection(type, alias, attr)} as ${this.quoteIdentifier(`${prefix2}${projection2[attr]}`)}`;
|
|
814
839
|
if (!as) {
|
|
815
|
-
as =
|
|
840
|
+
as = this.quoteIdentifier(`${prefix2}${projection2[attr]}`);
|
|
816
841
|
}
|
|
817
842
|
else {
|
|
818
|
-
as +=
|
|
843
|
+
as += `, ${this.quoteIdentifier(`${prefix2}${projection2[attr]}`)}`;
|
|
819
844
|
}
|
|
820
845
|
}
|
|
821
846
|
}
|
|
@@ -885,29 +910,29 @@ class SqlTranslator {
|
|
|
885
910
|
let { projText: projSubText } = this.translateProjection(entity, data[k], aliasDict, projectionRefAlias, undefined, true);
|
|
886
911
|
let projSubText2 = '';
|
|
887
912
|
if (k.startsWith('#max')) {
|
|
888
|
-
projSubText2 = `max(${projSubText}) as
|
|
913
|
+
projSubText2 = `max(${projSubText}) as ${this.quoteIdentifier(k)}`;
|
|
889
914
|
}
|
|
890
915
|
else if (k.startsWith('#min')) {
|
|
891
|
-
projSubText2 = `min(${projSubText}) as
|
|
916
|
+
projSubText2 = `min(${projSubText}) as ${this.quoteIdentifier(k)}`;
|
|
892
917
|
}
|
|
893
918
|
else if (k.startsWith('#count')) {
|
|
894
919
|
if (data.distinct) {
|
|
895
920
|
projSubText = `distinct ${projSubText}`;
|
|
896
921
|
}
|
|
897
|
-
projSubText2 = `count(${projSubText}) as
|
|
922
|
+
projSubText2 = `count(${projSubText}) as ${this.quoteIdentifier(k)}`;
|
|
898
923
|
}
|
|
899
924
|
else if (k.startsWith('#sum')) {
|
|
900
925
|
if (data.distinct) {
|
|
901
926
|
projSubText = `distinct ${projSubText}`;
|
|
902
927
|
}
|
|
903
|
-
projSubText2 = `sum(${projSubText}) as
|
|
928
|
+
projSubText2 = `sum(${projSubText}) as ${this.quoteIdentifier(k)}`;
|
|
904
929
|
}
|
|
905
930
|
else {
|
|
906
931
|
if (data.distinct) {
|
|
907
932
|
projSubText = `distinct ${projSubText}`;
|
|
908
933
|
}
|
|
909
934
|
(0, assert_1.default)(k.startsWith('#avg'));
|
|
910
|
-
projSubText2 = `avg(${projSubText}) as
|
|
935
|
+
projSubText2 = `avg(${projSubText}) as ${this.quoteIdentifier(k)}`;
|
|
911
936
|
}
|
|
912
937
|
if (!projText) {
|
|
913
938
|
projText = projSubText2;
|
|
@@ -955,7 +980,7 @@ class SqlTranslator {
|
|
|
955
980
|
// delete只支持对volatile trigger的metadata域赋值
|
|
956
981
|
(0, assert_1.default)([types_1.TriggerDataAttribute, types_1.TriggerUuidAttribute, types_1.DeleteAtAttribute, types_1.UpdateAtAttribute].includes(attr));
|
|
957
982
|
const value = this.translateAttrValue(attributes[attr].type, data[attr]);
|
|
958
|
-
updateText +=
|
|
983
|
+
updateText += `${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)} = ${value}`;
|
|
959
984
|
}
|
|
960
985
|
}
|
|
961
986
|
return this.populateRemoveStmt(updateText, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
|
|
@@ -973,7 +998,7 @@ class SqlTranslator {
|
|
|
973
998
|
}
|
|
974
999
|
(0, assert_1.default)(attributes.hasOwnProperty(attr));
|
|
975
1000
|
const value = this.translateAttrValue(attributes[attr].type, data[attr]);
|
|
976
|
-
updateText +=
|
|
1001
|
+
updateText += `${this.quoteIdentifier(alias)}.${this.quoteIdentifier(attr)} = ${value}`;
|
|
977
1002
|
}
|
|
978
1003
|
const { stmt: filterText } = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, option);
|
|
979
1004
|
// const sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
|
|
@@ -984,10 +1009,10 @@ class SqlTranslator {
|
|
|
984
1009
|
const { storageName = entity, view } = schema[entity];
|
|
985
1010
|
let sql;
|
|
986
1011
|
if (view) {
|
|
987
|
-
sql = `drop view if exists
|
|
1012
|
+
sql = `drop view if exists ${this.quoteIdentifier(storageName)}`;
|
|
988
1013
|
}
|
|
989
1014
|
else {
|
|
990
|
-
sql = truncate ? `truncate table
|
|
1015
|
+
sql = truncate ? `truncate table ${this.quoteIdentifier(storageName)}` : `drop table if exists ${this.quoteIdentifier(storageName)}`;
|
|
991
1016
|
}
|
|
992
1017
|
return sql;
|
|
993
1018
|
}
|
|
@@ -995,5 +1020,13 @@ class SqlTranslator {
|
|
|
995
1020
|
const result = sqlstring_1.default.escape(value);
|
|
996
1021
|
return result;
|
|
997
1022
|
}
|
|
1023
|
+
/**比较两段sql是否完全一致,这里是把所有的空格去掉了 */
|
|
1024
|
+
compareSql(sql1, sql2) {
|
|
1025
|
+
const reg = /[\t\r\f\n\s]/g;
|
|
1026
|
+
return sql1.replaceAll(reg, '') === sql2.replaceAll(reg, '');
|
|
1027
|
+
}
|
|
1028
|
+
quoteIdentifier(name) {
|
|
1029
|
+
return `\`${name}\``; // MySQL 默认
|
|
1030
|
+
}
|
|
998
1031
|
}
|
|
999
1032
|
exports.SqlTranslator = SqlTranslator;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type CreateEntityOption = {
|
|
2
|
-
ifExists?: 'drop' | 'omit' | 'dropIfNotStatic';
|
|
3
|
-
};
|
|
1
|
+
export type CreateEntityOption = {
|
|
2
|
+
ifExists?: 'drop' | 'omit' | 'dropIfNotStatic';
|
|
3
|
+
};
|
package/lib/types/Translator.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PostgreSQLConfiguration } from './../PostgreSQL/types/Configuration';
|
|
2
|
+
import { MySQLConfiguration } from './../MySQL/types/Configuration';
|
|
3
|
+
export type DbConfiguration = PostgreSQLConfiguration & {
|
|
4
|
+
type: 'postgresql';
|
|
5
|
+
} | MySQLConfiguration & {
|
|
6
|
+
type: 'mysql';
|
|
7
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EntityDict } from "oak-domain/lib/base-app-domain";
|
|
2
|
+
import { AsyncContext, AsyncRowStore } from "oak-domain/lib/store/AsyncRowStore";
|
|
3
|
+
import { CreateEntityOption } from "./Translator";
|
|
4
|
+
export interface DbStore<ED extends EntityDict, Cxt extends AsyncContext<ED>> extends AsyncRowStore<ED, Cxt> {
|
|
5
|
+
connect: () => Promise<void>;
|
|
6
|
+
disconnect: () => Promise<void>;
|
|
7
|
+
initialize(options: CreateEntityOption): Promise<void>;
|
|
8
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oak-db",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.12",
|
|
4
4
|
"description": "oak-db",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"author": {
|
|
@@ -10,15 +10,16 @@
|
|
|
10
10
|
"lib/**/*"
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
|
-
"test": "mocha",
|
|
13
|
+
"test": "node --stack-size=65500 ./node_modules/mocha/bin/mocha",
|
|
14
14
|
"make:test:domain": "ts-node script/makeTestDomain.ts",
|
|
15
|
-
"build": "
|
|
15
|
+
"build": "node --stack-size=4096 ./script/build.js"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"lodash": "^4.17.21",
|
|
19
19
|
"mysql": "^2.18.1",
|
|
20
20
|
"mysql2": "^2.3.3",
|
|
21
|
-
"oak-domain": "^5.1.
|
|
21
|
+
"oak-domain": "^5.1.33",
|
|
22
|
+
"pg": "^8.16.3",
|
|
22
23
|
"uuid": "^8.3.2"
|
|
23
24
|
},
|
|
24
25
|
"license": "ISC",
|
|
@@ -27,11 +28,11 @@
|
|
|
27
28
|
"@types/luxon": "^2.3.2",
|
|
28
29
|
"@types/mocha": "^9.1.1",
|
|
29
30
|
"@types/node": "^20.6.0",
|
|
31
|
+
"@types/pg": "^8.16.0",
|
|
30
32
|
"@types/sqlstring": "^2.3.0",
|
|
31
33
|
"@types/uuid": "^8.3.4",
|
|
32
34
|
"cross-env": "^7.0.3",
|
|
33
35
|
"mocha": "^10.2.0",
|
|
34
|
-
"oak-general-business": "~5.5.0",
|
|
35
36
|
"ts-node": "^10.9.1",
|
|
36
37
|
"tslib": "^2.4.0",
|
|
37
38
|
"typescript": "^5.2.2"
|