oak-db 2.2.10 → 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.
@@ -10,6 +10,7 @@ export declare class MysqlStore<ED extends EntityDict & BaseEntityDict, Cxt exte
10
10
  protected aggregateSync<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): AggregationResult<ED[T]['Schema']>;
11
11
  protected selectAbjointRow<T extends keyof ED, OP extends SelectOption>(entity: T, selection: ED[T]['Selection'], context: SyncContext<ED>, option: OP): Partial<ED[T]['Schema']>[];
12
12
  protected updateAbjointRow<T extends keyof ED, OP extends OperateOption>(entity: T, operation: ED[T]['Operation'], context: SyncContext<ED>, option: OP): number;
13
+ exec(script: string, txnId?: string): Promise<any>;
13
14
  connector: MySqlConnector;
14
15
  translator: MySqlTranslator<ED>;
15
16
  constructor(storageSchema: StorageSchema<ED>, configuration: MySQLConfiguration);
@@ -37,6 +37,9 @@ var MysqlStore = /** @class */ (function (_super) {
37
37
  MysqlStore.prototype.updateAbjointRow = function (entity, operation, context, option) {
38
38
  throw new Error('MySQL store不支持同步更新数据,不应该跑到这儿');
39
39
  };
40
+ MysqlStore.prototype.exec = function (script, txnId) {
41
+ return this.connector.exec(script, txnId);
42
+ };
40
43
  MysqlStore.prototype.aggregateAsync = function (entity, aggregation, context, option) {
41
44
  return tslib_1.__awaiter(this, void 0, void 0, function () {
42
45
  var sql, result;
@@ -63,6 +66,25 @@ var MysqlStore = /** @class */ (function (_super) {
63
66
  };
64
67
  MysqlStore.prototype.formResult = function (entity, result) {
65
68
  var schema = this.getSchema();
69
+ /* function resolveObject(r: Record<string, any>, path: string, value: any) {
70
+ const i = path.indexOf(".");
71
+ const bs = path.indexOf('[');
72
+ const be = path.indexOf(']');
73
+ if (i === -1 && bs === -1) {
74
+ r[i] = value;
75
+ }
76
+ else if (i === -1) {
77
+
78
+ }
79
+ else if (bs === -1) {
80
+ const attrHead = path.slice(0, i);
81
+ const attrTail = path.slice(i + 1);
82
+ if (!r[attrHead]) {
83
+ r[attrHead] = {};
84
+ }
85
+ resolveObject(r[attrHead], attrTail, value);
86
+ }
87
+ } */
66
88
  function resolveAttribute(entity2, r, attr, value) {
67
89
  var _a;
68
90
  var _b = schema[entity2], attributes = _b.attributes, view = _b.view;
@@ -71,19 +93,24 @@ var MysqlStore = /** @class */ (function (_super) {
71
93
  if (i !== -1) {
72
94
  var attrHead = attr.slice(0, i);
73
95
  var attrTail = attr.slice(i + 1);
74
- if (!r[attrHead]) {
75
- r[attrHead] = {};
76
- }
77
96
  var rel = (0, relation_1.judgeRelation)(schema, entity2, attrHead);
78
- if (rel === 0) {
79
- resolveAttribute(entity2, r[attrHead], attrTail, value);
80
- }
81
- else if (rel === 2) {
82
- resolveAttribute(attrHead, r[attrHead], attrTail, value);
97
+ if (rel === 1) {
98
+ (0, lodash_1.set)(r, attr, value);
83
99
  }
84
100
  else {
85
- (0, assert_1.default)(typeof rel === 'string');
86
- resolveAttribute(rel, r[attrHead], attrTail, value);
101
+ if (!r[attrHead]) {
102
+ r[attrHead] = {};
103
+ }
104
+ if (rel === 0) {
105
+ resolveAttribute(entity2, r[attrHead], attrTail, value);
106
+ }
107
+ else if (rel === 2) {
108
+ resolveAttribute(attrHead, r[attrHead], attrTail, value);
109
+ }
110
+ else {
111
+ (0, assert_1.default)(typeof rel === 'string');
112
+ resolveAttribute(rel, r[attrHead], attrTail, value);
113
+ }
87
114
  }
88
115
  }
89
116
  else if (attributes[attr]) {
@@ -141,6 +168,17 @@ var MysqlStore = /** @class */ (function (_super) {
141
168
  }
142
169
  break;
143
170
  }
171
+ case 'decimal': {
172
+ // mysql内部取回decimal是字符串
173
+ if (typeof value === 'string') {
174
+ r[attr] = parseFloat(value);
175
+ }
176
+ else {
177
+ (0, assert_1.default)(value === null || typeof value === 'number');
178
+ r[attr] = value;
179
+ }
180
+ break;
181
+ }
144
182
  default: {
145
183
  r[attr] = value;
146
184
  }
@@ -283,7 +321,7 @@ var MysqlStore = /** @class */ (function (_super) {
283
321
  case 0:
284
322
  action = operation.action;
285
323
  (0, assert_1.default)(!['select', 'download', 'stat'].includes(action), '现在不支持使用select operation');
286
- return [4 /*yield*/, this.cascadeUpdateAsync(entity, operation, context, option)];
324
+ return [4 /*yield*/, _super.prototype.operateAsync.call(this, entity, operation, context, option)];
287
325
  case 1: return [2 /*return*/, _a.sent()];
288
326
  }
289
327
  });
@@ -294,7 +332,7 @@ var MysqlStore = /** @class */ (function (_super) {
294
332
  var result;
295
333
  return tslib_1.__generator(this, function (_a) {
296
334
  switch (_a.label) {
297
- case 0: return [4 /*yield*/, this.cascadeSelectAsync(entity, selection, context, option)];
335
+ case 0: return [4 /*yield*/, _super.prototype.selectAsync.call(this, entity, selection, context, option)];
298
336
  case 1:
299
337
  result = _a.sent();
300
338
  return [2 /*return*/, result];
@@ -1,11 +1,12 @@
1
1
  import { EntityDict, Q_FullTextValue, RefOrExpression, Ref, StorageSchema } from "oak-domain/lib/types";
2
+ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
2
3
  import { DataType } from "oak-domain/lib/types/schema/DataTypes";
3
4
  import { SqlOperateOption, SqlSelectOption, SqlTranslator } from "../sqlTranslator";
4
5
  export interface MySqlSelectOption extends SqlSelectOption {
5
6
  }
6
7
  export interface MysqlOperateOption extends SqlOperateOption {
7
8
  }
8
- export declare class MySqlTranslator<ED extends EntityDict> extends SqlTranslator<ED> {
9
+ export declare class MySqlTranslator<ED extends EntityDict & BaseEntityDict> extends SqlTranslator<ED> {
9
10
  protected getDefaultSelectFilter(alias: string, option?: MySqlSelectOption): string;
10
11
  private makeUpSchema;
11
12
  constructor(schema: StorageSchema<ED>);
@@ -91,6 +92,8 @@ export declare class MySqlTranslator<ED extends EntityDict> extends SqlTranslato
91
92
  maxAliasLength: number;
92
93
  private populateDataTypeDef;
93
94
  protected translateAttrProjection(dataType: DataType, alias: string, attr: string): string;
95
+ protected translateObjectPredicate(predicate: Record<string, any>, alias: string, attr: string): string;
96
+ protected translateObjectProjection(projection: Record<string, any>, alias: string, attr: string, prefix: string): string;
94
97
  protected translateAttrValue(dataType: DataType | Ref, value: any): string;
95
98
  protected translateFullTextSearch<T extends keyof ED>(value: Q_FullTextValue, entity: T, alias: string): string;
96
99
  translateCreateEntity<T extends keyof ED>(entity: T, options?: {
@@ -128,7 +128,7 @@ var MySqlTranslator = /** @class */ (function (_super) {
128
128
  return 'bigint ';
129
129
  }
130
130
  if (['object', 'array'].includes(type)) {
131
- return 'text ';
131
+ return 'json ';
132
132
  }
133
133
  if (['image', 'function'].includes(type)) {
134
134
  return 'text ';
@@ -202,6 +202,121 @@ var MySqlTranslator = /** @class */ (function (_super) {
202
202
  }
203
203
  }
204
204
  };
205
+ MySqlTranslator.prototype.translateObjectPredicate = function (predicate, alias, attr) {
206
+ var _this = this;
207
+ var stmt = '';
208
+ var translatePredicate = function (o, p) {
209
+ var predicate2 = Object.keys(o)[0];
210
+ if (predicate2.startsWith('$')) {
211
+ if (stmt) {
212
+ stmt += ' and ';
213
+ }
214
+ // todo
215
+ if (predicate2 === '$contains') {
216
+ // json_contains,多值的包含关系
217
+ var value = JSON.stringify(o[predicate2]);
218
+ stmt += "JSON_CONTAINS(".concat(alias, ".").concat(attr, "->>\"$").concat(p, "\", CAST('").concat(value, "' AS JSON)) ");
219
+ }
220
+ else if (predicate2 === '$overlaps') {
221
+ // json_overlaps,多值的交叉关系
222
+ var value = JSON.stringify(o[predicate2]);
223
+ stmt += "JSON_OVERLAPS(".concat(alias, ".").concat(attr, "->>\"$").concat(p, "\", CAST('").concat(value, "' AS JSON)) ");
224
+ }
225
+ else {
226
+ stmt += "".concat(alias, ".").concat(attr, "->>\"$").concat(p, "\" ").concat(_this.translatePredicate(predicate2, o[predicate2]));
227
+ }
228
+ }
229
+ else {
230
+ // 继续子对象解构
231
+ translateInner(o, p);
232
+ }
233
+ };
234
+ var translateInner = function (o, p) {
235
+ if (o instanceof Array) {
236
+ o.forEach(function (item, idx) {
237
+ var p2 = "".concat(p, "[").concat(idx, "]");
238
+ if (typeof item !== 'object') {
239
+ if (item !== null && item !== undefined) {
240
+ if (stmt) {
241
+ stmt += ' and ';
242
+ }
243
+ stmt += "".concat(alias, ".").concat(attr, "->>\"$").concat(p2, "\"");
244
+ if (typeof item === 'string') {
245
+ stmt += " = '".concat(item, "'");
246
+ }
247
+ else {
248
+ stmt += " = ".concat(item);
249
+ }
250
+ }
251
+ }
252
+ else {
253
+ translatePredicate(item, p2);
254
+ }
255
+ });
256
+ }
257
+ else {
258
+ for (var key in o) {
259
+ var p2 = "".concat(p, ".").concat(key);
260
+ if (typeof o[key] !== 'object') {
261
+ if (o[key] !== null && o[key] !== undefined) {
262
+ if (stmt) {
263
+ stmt += ', ';
264
+ }
265
+ stmt += "".concat(alias, ".").concat(attr, "->>\"$").concat(p2, "\"");
266
+ if (typeof o[key] === 'string') {
267
+ stmt += " = '".concat(o[key], "'");
268
+ }
269
+ else {
270
+ stmt += " = ".concat(o[key]);
271
+ }
272
+ }
273
+ }
274
+ else {
275
+ translatePredicate(o[key], p2);
276
+ }
277
+ }
278
+ }
279
+ };
280
+ translatePredicate(predicate, '');
281
+ return stmt;
282
+ };
283
+ MySqlTranslator.prototype.translateObjectProjection = function (projection, alias, attr, prefix) {
284
+ var stmt = '';
285
+ var translateInner = function (o, p) {
286
+ if (o instanceof Array) {
287
+ o.forEach(function (item, idx) {
288
+ var p2 = "".concat(p, "[").concat(idx, "]");
289
+ if (typeof item === 'number') {
290
+ if (stmt) {
291
+ stmt += ', ';
292
+ }
293
+ stmt += "".concat(alias, ".").concat(attr, "->>\"$").concat(p2, "\"");
294
+ stmt += prefix ? " as `".concat(prefix, ".").concat(attr).concat(p2, "`") : " as `".concat(attr).concat(p2, "`");
295
+ }
296
+ else if (typeof item === 'object') {
297
+ translateInner(item, p2);
298
+ }
299
+ });
300
+ }
301
+ else {
302
+ for (var key in o) {
303
+ var p2 = "".concat(p, ".").concat(key);
304
+ if (typeof o[key] === 'number') {
305
+ if (stmt) {
306
+ stmt += ', ';
307
+ }
308
+ stmt += "".concat(alias, ".").concat(attr, "->>\"$").concat(p2, "\"");
309
+ stmt += prefix ? " as `".concat(prefix, ".").concat(attr).concat(p2, "`") : " as `".concat(attr).concat(p2, "`");
310
+ }
311
+ else {
312
+ translateInner(o[key], p2);
313
+ }
314
+ }
315
+ }
316
+ };
317
+ translateInner(projection, '');
318
+ return stmt;
319
+ };
205
320
  MySqlTranslator.prototype.translateAttrValue = function (dataType, value) {
206
321
  if (value === null || value === undefined) {
207
322
  return 'null';
@@ -1,20 +1,23 @@
1
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';
2
3
  import { DataType } from "oak-domain/lib/types/schema/DataTypes";
3
4
  export interface SqlSelectOption extends SelectOption {
4
5
  }
5
6
  export interface SqlOperateOption extends OperateOption {
6
7
  }
7
- export declare abstract class SqlTranslator<ED extends EntityDict> {
8
+ export declare abstract class SqlTranslator<ED extends EntityDict & BaseEntityDict> {
8
9
  readonly schema: StorageSchema<ED>;
9
10
  constructor(schema: StorageSchema<ED>);
10
11
  private makeFullSchema;
11
12
  protected abstract getDefaultSelectFilter<OP extends SqlSelectOption>(alias: string, option?: OP): string;
12
13
  protected abstract translateAttrProjection(dataType: DataType, alias: string, attr: string): string;
14
+ protected abstract translateObjectProjection(projection: Record<string, any>, alias: string, attr: string, prefix: string): string;
13
15
  protected abstract translateAttrValue(dataType: DataType | Ref, value: any): string;
14
16
  protected abstract translateFullTextSearch<T extends keyof ED>(value: Q_FullTextValue, entity: T, alias: string): string;
15
17
  abstract translateCreateEntity<T extends keyof ED>(entity: T, option: {
16
18
  replace?: boolean;
17
19
  }): string[];
20
+ protected abstract translateObjectPredicate(predicate: Record<string, any>, alias: string, attr: string): string;
18
21
  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;
19
22
  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;
20
23
  protected abstract populateRemoveStmt<OP extends SqlOperateOption>(removeText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
@@ -36,8 +39,8 @@ export declare abstract class SqlTranslator<ED extends EntityDict> {
36
39
  */
37
40
  private analyzeJoin;
38
41
  private translateComparison;
39
- private translateElement;
40
42
  private translateEvaluation;
43
+ protected translatePredicate(predicate: string, value: any, type?: DataType | Ref): string;
41
44
  private translateFilter;
42
45
  private translateSorter;
43
46
  private translateProjection;
@@ -6,6 +6,7 @@ var assert_1 = tslib_1.__importDefault(require("assert"));
6
6
  var lodash_1 = require("lodash");
7
7
  var types_1 = require("oak-domain/lib/types");
8
8
  var relation_1 = require("oak-domain/lib/store/relation");
9
+ var filter_1 = require("oak-domain/lib/store/filter");
9
10
  ;
10
11
  ;
11
12
  var SqlTranslator = /** @class */ (function () {
@@ -207,7 +208,6 @@ var SqlTranslator = /** @class */ (function () {
207
208
  var number = initialNumber || 1;
208
209
  var projectionRefAlias = {};
209
210
  var filterRefAlias = {};
210
- var extraWhere = '';
211
211
  var alias = "".concat(entity, "_").concat(number++);
212
212
  var from = " `".concat(this.getStorageName(entity), "` `").concat(alias, "` ");
213
213
  var aliasDict = {
@@ -280,7 +280,7 @@ var SqlTranslator = /** @class */ (function () {
280
280
  }
281
281
  else {
282
282
  // 不支持一对多
283
- (0, assert_1.default)(rel === 0 || rel === 1);
283
+ // assert(rel === 0 || rel === 1);
284
284
  }
285
285
  }
286
286
  });
@@ -431,7 +431,6 @@ var SqlTranslator = /** @class */ (function () {
431
431
  from: from,
432
432
  projectionRefAlias: projectionRefAlias,
433
433
  filterRefAlias: filterRefAlias,
434
- extraWhere: extraWhere,
435
434
  currentNumber: number,
436
435
  };
437
436
  };
@@ -445,7 +444,12 @@ var SqlTranslator = /** @class */ (function () {
445
444
  $ne: '<>',
446
445
  };
447
446
  if (Object.keys(SQL_OP).includes(attr)) {
448
- return " ".concat(SQL_OP[attr], " ").concat(this.translateAttrValue(type, value));
447
+ if (type) {
448
+ return " ".concat(SQL_OP[attr], " ").concat(this.translateAttrValue(type, value));
449
+ }
450
+ else {
451
+ return " ".concat(SQL_OP[attr], " ").concat(value);
452
+ }
449
453
  }
450
454
  switch (attr) {
451
455
  case '$startsWith': {
@@ -462,22 +466,8 @@ var SqlTranslator = /** @class */ (function () {
462
466
  }
463
467
  }
464
468
  };
465
- SqlTranslator.prototype.translateElement = function (attr, value) {
466
- (0, assert_1.default)(attr === '$exists'); // only support one operator now
467
- if (value) {
468
- return ' is not null';
469
- }
470
- return ' is null';
471
- };
472
469
  SqlTranslator.prototype.translateEvaluation = function (attr, value, entity, alias, type, initialNumber, refAlias) {
473
470
  switch (attr) {
474
- case '$text': {
475
- // fulltext search
476
- return {
477
- stmt: this.translateFullTextSearch(value, entity, alias),
478
- currentNumber: initialNumber,
479
- };
480
- }
481
471
  case '$in':
482
472
  case '$nin': {
483
473
  var IN_OP = {
@@ -485,65 +475,75 @@ var SqlTranslator = /** @class */ (function () {
485
475
  $nin: 'not in',
486
476
  };
487
477
  if (value instanceof Array) {
488
- var values = value.map(function (v) {
489
- if (['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type)) {
490
- return "'".concat(v, "'");
491
- }
492
- else {
493
- return "".concat(v);
494
- }
495
- });
496
- if (values.length > 0) {
497
- return {
498
- stmt: " ".concat(IN_OP[attr], "(").concat(values.join(','), ")"),
499
- currentNumber: initialNumber,
500
- };
501
- }
502
- else {
503
- if (attr === '$in') {
504
- return {
505
- stmt: ' in (null)',
506
- currentNumber: initialNumber,
507
- };
508
- }
509
- else {
510
- return {
511
- stmt: ' is not null',
512
- currentNumber: initialNumber,
513
- };
514
- }
515
- }
478
+ return {
479
+ stmt: this.translatePredicate(attr, value, type),
480
+ currentNumber: initialNumber,
481
+ };
516
482
  }
517
483
  else {
484
+ (0, assert_1.default)(false, '子查询已经改写为一对多的形式');
518
485
  // sub query
519
- var _a = this.translateSelectInner(value.entity, value, initialNumber, refAlias, undefined), subQueryStmt = _a.stmt, currentNumber = _a.currentNumber;
486
+ /* const { stmt: subQueryStmt, currentNumber } = this.translateSelectInner(value.entity, value, initialNumber, refAlias, undefined);
520
487
  return {
521
- stmt: " ".concat(IN_OP[attr], "(").concat(subQueryStmt, ")"),
522
- currentNumber: currentNumber,
523
- };
488
+ stmt: ` ${IN_OP[attr]}(${subQueryStmt})`,
489
+ currentNumber,
490
+ }; */
524
491
  }
525
492
  }
526
493
  default: {
527
- (0, assert_1.default)('$between' === attr);
528
- var values = value.map(function (v) {
529
- if (['varchar', 'char', 'text', 'nvarchar', 'ref'].includes(type)) {
530
- return "'".concat(v, "'");
531
- }
532
- else {
533
- return "".concat(v);
534
- }
535
- });
536
- return {
537
- stmt: " between ".concat(values[0], " and ").concat(values[1]),
538
- currentNumber: initialNumber,
539
- };
494
+ throw new Error("".concat(attr, " is not evaluation predicate"));
540
495
  }
541
496
  }
542
497
  };
543
- SqlTranslator.prototype.translateFilter = function (entity, selection, aliasDict, filterRefAlias, initialNumber, extraWhere, option) {
498
+ SqlTranslator.prototype.translatePredicate = function (predicate, value, type) {
499
+ if (['$gt', '$gte', '$lt', '$lte', '$eq', '$ne', '$startsWith', '$endsWith', '$includes'].includes(predicate)) {
500
+ return this.translateComparison(predicate, value, type);
501
+ }
502
+ else if (['$in', '$nin'].includes(predicate)) {
503
+ (0, assert_1.default)(value instanceof Array);
504
+ var IN_OP = {
505
+ $in: 'in',
506
+ $nin: 'not in',
507
+ };
508
+ var values = value.map(function (v) {
509
+ if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
510
+ return "'".concat(v, "'");
511
+ }
512
+ else {
513
+ return "".concat(v);
514
+ }
515
+ });
516
+ if (values.length > 0) {
517
+ return " ".concat(IN_OP[predicate], "(").concat(values.join(','), ")");
518
+ }
519
+ if (predicate === '$in') {
520
+ return ' in (null)';
521
+ }
522
+ return ' is not null';
523
+ }
524
+ else if (predicate === '$between') {
525
+ var values = value.map(function (v) {
526
+ if (type && ['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type) || typeof v === 'string') {
527
+ return "'".concat(v, "'");
528
+ }
529
+ else {
530
+ return "".concat(v);
531
+ }
532
+ });
533
+ // between是所有数据库都支持的语法吗?
534
+ return " between ".concat(values[0], " and ").concat(values[1]);
535
+ }
536
+ else {
537
+ (0, assert_1.default)(predicate === '$exists');
538
+ if (value) {
539
+ return ' is not null';
540
+ }
541
+ return ' is null';
542
+ }
543
+ };
544
+ SqlTranslator.prototype.translateFilter = function (entity, filter, aliasDict, filterRefAlias, initialNumber, option) {
544
545
  var _this = this;
545
546
  var schema = this.schema;
546
- var filter = selection.filter;
547
547
  var currentNumber = initialNumber;
548
548
  var translateInner = function (entity2, path, filter2, type) {
549
549
  var alias = aliasDict[path];
@@ -552,11 +552,11 @@ var SqlTranslator = /** @class */ (function () {
552
552
  if (filter2) {
553
553
  var attrs = Object.keys(filter2).filter(function (ele) { return !ele.startsWith('#'); });
554
554
  attrs.forEach(function (attr) {
555
+ var _a;
555
556
  if (whereText) {
556
557
  whereText += ' and ';
557
558
  }
558
559
  if (['$and', '$or', '$xor', '$not'].includes(attr)) {
559
- var result = '';
560
560
  whereText += '(';
561
561
  switch (attr) {
562
562
  case '$and':
@@ -564,7 +564,7 @@ var SqlTranslator = /** @class */ (function () {
564
564
  case '$xor': {
565
565
  var logicQueries_1 = filter2[attr];
566
566
  logicQueries_1.forEach(function (logicQuery, index) {
567
- var sql = translateInner(entity2, path, logicQuery);
567
+ var sql = translateInner(entity2, path, logicQuery, 'ref'); // 只要传个值就行了,应该无所谓
568
568
  if (sql) {
569
569
  whereText += " (".concat(sql, ")");
570
570
  if (index < logicQueries_1.length - 1) {
@@ -577,30 +577,22 @@ var SqlTranslator = /** @class */ (function () {
577
577
  default: {
578
578
  (0, assert_1.default)(attr === '$not');
579
579
  var logicQuery = filter2[attr];
580
- var sql = translateInner(entity2, path, logicQuery);
580
+ var sql = translateInner(entity2, path, logicQuery, 'ref'); // 只要传个值就行了,应该无所谓
581
581
  if (sql) {
582
- whereText += " not (".concat(translateInner(entity2, path, logicQuery), ")");
582
+ whereText += " not (".concat(sql, ")");
583
583
  break;
584
584
  }
585
585
  }
586
586
  }
587
587
  whereText += ')';
588
588
  }
589
+ else if (attr === '$text') {
590
+ whereText += "(".concat(_this.translateFullTextSearch(filter2[attr], entity2, alias), ")");
591
+ }
589
592
  else if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
590
593
  // expression
591
594
  whereText += " (".concat(_this.translateExpression(entity2, alias, filter2[attr], filterRefAlias), ")");
592
595
  }
593
- else if (['$gt', '$gte', '$lt', '$lte', '$eq', '$ne', '$startsWith', '$endsWith', '$includes'].includes(attr)) {
594
- whereText += _this.translateComparison(attr, filter2[attr], type);
595
- }
596
- else if (['$exists'].includes(attr)) {
597
- whereText += _this.translateElement(attr, filter2[attr]);
598
- }
599
- else if (['$text', '$in', '$nin', '$between'].includes(attr)) {
600
- var _a = _this.translateEvaluation(attr, filter2[attr], entity2, alias, type, initialNumber, filterRefAlias), stmt = _a.stmt, cn2 = _a.currentNumber;
601
- whereText += stmt;
602
- currentNumber = cn2;
603
- }
604
596
  else {
605
597
  var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
606
598
  if (rel === 2) {
@@ -609,12 +601,91 @@ var SqlTranslator = /** @class */ (function () {
609
601
  else if (typeof rel === 'string') {
610
602
  whereText += " (".concat(translateInner(rel, "".concat(path).concat(attr, "/"), filter2[attr]), ")");
611
603
  }
604
+ else if (rel instanceof Array) {
605
+ var subEntity = rel[0], foreignKey = rel[1];
606
+ var predicate = (filter2[attr]['#sqp'] || 'in');
607
+ /**
608
+ *
609
+ * in代表外键连接后至少有一行数据
610
+ * not in代表外键连接后一行也不能有
611
+ * all代表反外键连接条件的一行也不能有(符合的是否至少要有一行?直觉上没这个限制)
612
+ * not all 代表反外键连接条件的至少有一行
613
+ *
614
+ * 目前将这种子查询翻译成了exists查询,当外表很大而子查询结果集很小时可能有性能问题,取决于MySQL执行器的能力
615
+ * by Xc 20230726
616
+ */
617
+ var refAlia = Object.keys(filterRefAlias).find(function (ele) { return filterRefAlias[ele][0] === alias; });
618
+ var refAlia2 = refAlia || alias; // alias一定是唯一的,可以用来作为node id
619
+ if (!refAlia) {
620
+ (0, assert_1.default)(!filterRefAlias[refAlia2]);
621
+ Object.assign(filterRefAlias, (_a = {},
622
+ _a[refAlia2] = [alias, entity2],
623
+ _a));
624
+ }
625
+ var fk = foreignKey || 'entityId';
626
+ var joinFilter = ['not in', 'in'].includes(predicate) ? {
627
+ $expr12: {
628
+ $eq: [
629
+ {
630
+ '#attr': fk,
631
+ },
632
+ {
633
+ '#refId': refAlia2,
634
+ '#refAttr': 'id',
635
+ }
636
+ ],
637
+ }
638
+ } : {
639
+ $expr12: {
640
+ $ne: [
641
+ {
642
+ '#attr': fk,
643
+ },
644
+ {
645
+ '#refId': refAlia2,
646
+ '#refAttr': 'id',
647
+ }
648
+ ],
649
+ }
650
+ };
651
+ if (!foreignKey) {
652
+ Object.assign(joinFilter, {
653
+ entity: entity2,
654
+ });
655
+ }
656
+ var _b = _this.translateSelectInner(subEntity, {
657
+ data: {
658
+ id: 1,
659
+ },
660
+ filter: (0, filter_1.combineFilters)(subEntity, _this.schema, [joinFilter, filter2[attr]]),
661
+ indexFrom: 0,
662
+ count: 1,
663
+ }, currentNumber, filterRefAlias, option), stmt = _b.stmt, ct2 = _b.currentNumber;
664
+ currentNumber = ct2;
665
+ var PREDICATE_DICT = {
666
+ 'in': 'exists',
667
+ 'not in': 'not exists',
668
+ 'all': 'not exists',
669
+ 'not all': 'exists',
670
+ };
671
+ whereText += " ".concat(PREDICATE_DICT[predicate], " (").concat(stmt, ")");
672
+ }
612
673
  else {
613
674
  (0, assert_1.default)(attributes.hasOwnProperty(attr), "\u975E\u6CD5\u7684\u5C5E\u6027".concat(attr));
614
675
  var type2 = attributes[attr].type;
615
- // assert (type2 !== 'ref');
616
- if (typeof filter2[attr] === 'object' && Object.keys(filter2[attr])[0] && Object.keys(filter2[attr])[0].startsWith('$')) {
617
- whereText += " (`".concat(alias, "`.`").concat(attr, "` ").concat(translateInner(entity2, path, filter2[attr], type2), ")");
676
+ // assert (type2 !== 'ref');
677
+ if (typeof filter2[attr] === 'object') {
678
+ if (['object', 'array'].includes(type2)) {
679
+ // 对object数据的深层次查询,这里调用数据库所支持的属性对象级查询,如mysql中的json查询
680
+ whereText += "(".concat(_this.translateObjectPredicate(filter2[attr], alias, attr), ")");
681
+ }
682
+ else {
683
+ (0, assert_1.default)(Object.keys(filter2[attr]).length === 1);
684
+ var predicate = Object.keys(filter2[attr])[0];
685
+ (0, assert_1.default)(predicate.startsWith('$'));
686
+ // 对属性上的谓词处理
687
+ whereText += " (`".concat(alias, "`.`").concat(attr, "` ").concat(_this.translatePredicate(predicate, filter2[attr][predicate], type2), ")");
688
+ }
618
689
  }
619
690
  else {
620
691
  whereText += " (`".concat(alias, "`.`").concat(attr, "` = ").concat(_this.translateAttrValue(type2, filter2[attr]), ")");
@@ -629,14 +700,8 @@ var SqlTranslator = /** @class */ (function () {
629
700
  return whereText;
630
701
  };
631
702
  var where = translateInner(entity, './', filter);
632
- if (extraWhere && where) {
633
- return {
634
- stmt: "".concat(extraWhere, " and ").concat(where),
635
- currentNumber: currentNumber,
636
- };
637
- }
638
703
  return {
639
- stmt: extraWhere || where,
704
+ stmt: where,
640
705
  currentNumber: currentNumber,
641
706
  };
642
707
  };
@@ -733,6 +798,12 @@ var SqlTranslator = /** @class */ (function () {
733
798
  }
734
799
  }
735
800
  }
801
+ else if (typeof projection2[attr] === 'object') {
802
+ // 对JSON对象的取值
803
+ (0, assert_1.default)(!disableAs);
804
+ (0, assert_1.default)(['object', 'array'].includes(type));
805
+ projText += " ".concat(_this.translateObjectProjection(projection2[attr], alias, attr, prefix2));
806
+ }
736
807
  else {
737
808
  (0, assert_1.default)(typeof projection2 === 'string');
738
809
  if (disableAs) {
@@ -767,11 +838,11 @@ var SqlTranslator = /** @class */ (function () {
767
838
  projection: data,
768
839
  filter: filter,
769
840
  sorter: sorter,
770
- }, initialNumber), fromText = _a.from, aliasDict = _a.aliasDict, projectionRefAlias = _a.projectionRefAlias, extraWhere = _a.extraWhere, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
841
+ }, initialNumber), fromText = _a.from, aliasDict = _a.aliasDict, projectionRefAlias = _a.projectionRefAlias, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
771
842
  (0, assert_1.default)((0, lodash_1.intersection)((0, lodash_1.keys)(refAlias), (0, lodash_1.keys)(filterRefAlias)).length === 0, 'filter中的#node结点定义有重复');
772
843
  (0, lodash_1.assign)(refAlias, filterRefAlias);
773
844
  var projText = this.translateProjection(entity, data, aliasDict, projectionRefAlias).projText;
774
- var _b = this.translateFilter(entity, selection, aliasDict, refAlias, currentNumber, extraWhere, option), filterText = _b.stmt, currentNumber2 = _b.currentNumber;
845
+ var _b = this.translateFilter(entity, filter, aliasDict, refAlias, currentNumber, option), filterText = _b.stmt, currentNumber2 = _b.currentNumber;
775
846
  var sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
776
847
  return {
777
848
  stmt: this.populateSelectStmt(projText, fromText, aliasDict, filterText, sorterText, undefined, indexFrom, count, option, selection),
@@ -793,7 +864,7 @@ var SqlTranslator = /** @class */ (function () {
793
864
  aggregation: data,
794
865
  filter: filter,
795
866
  sorter: sorter,
796
- }, 1), fromText = _a.from, aliasDict = _a.aliasDict, projectionRefAlias = _a.projectionRefAlias, extraWhere = _a.extraWhere, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
867
+ }, 1), fromText = _a.from, aliasDict = _a.aliasDict, projectionRefAlias = _a.projectionRefAlias, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
797
868
  var projText = '';
798
869
  var groupByText = '';
799
870
  for (var k in data) {
@@ -834,7 +905,7 @@ var SqlTranslator = /** @class */ (function () {
834
905
  }
835
906
  }
836
907
  }
837
- var filterText = this.translateFilter(entity, aggregation, aliasDict, {}, currentNumber, extraWhere, option).stmt;
908
+ var filterText = this.translateFilter(entity, filter, aliasDict, {}, currentNumber, option).stmt;
838
909
  var sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
839
910
  return this.populateSelectStmt(projText, fromText, aliasDict, filterText, sorterText, groupByText, indexFrom, count, option, undefined, aggregation);
840
911
  };
@@ -842,9 +913,9 @@ var SqlTranslator = /** @class */ (function () {
842
913
  var filter = selection.filter, count = selection.count;
843
914
  var _a = this.analyzeJoin(entity, {
844
915
  filter: filter,
845
- }), fromText = _a.from, aliasDict = _a.aliasDict, extraWhere = _a.extraWhere, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
916
+ }), fromText = _a.from, aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
846
917
  var projText = 'count(1) cnt';
847
- var filterText = this.translateFilter(entity, selection, aliasDict, filterRefAlias, currentNumber, extraWhere, option).stmt;
918
+ var filterText = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, option).stmt;
848
919
  if (count) {
849
920
  var subQuerySql = this.populateSelectStmt('1', fromText, aliasDict, filterText, undefined, undefined, undefined, undefined, option, Object.assign({}, selection, { indexFrom: 0, count: count }));
850
921
  return "select count(1) cnt from (".concat(subQuerySql, ") __tmp");
@@ -854,9 +925,9 @@ var SqlTranslator = /** @class */ (function () {
854
925
  SqlTranslator.prototype.translateRemove = function (entity, operation, option) {
855
926
  var filter = operation.filter, sorter = operation.sorter, indexFrom = operation.indexFrom, count = operation.count;
856
927
  (0, assert_1.default)(!sorter, '当前remove不支持sorter行为');
857
- var _a = this.analyzeJoin(entity, { filter: filter, sorter: sorter }), aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, extraWhere = _a.extraWhere, fromText = _a.from, currentNumber = _a.currentNumber;
928
+ var _a = this.analyzeJoin(entity, { filter: filter, sorter: sorter }), aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, fromText = _a.from, currentNumber = _a.currentNumber;
858
929
  var alias = aliasDict['./'];
859
- var filterText = this.translateFilter(entity, operation, aliasDict, filterRefAlias, currentNumber, extraWhere, { includedDeleted: true }).stmt;
930
+ var filterText = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber, { includedDeleted: true }).stmt;
860
931
  // const sorterText = sorter && sorter.length > 0 ? this.translateSorter(entity, sorter, aliasDict) : undefined;
861
932
  return this.populateRemoveStmt(alias, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
862
933
  };
@@ -864,7 +935,7 @@ var SqlTranslator = /** @class */ (function () {
864
935
  var attributes = this.schema[entity].attributes;
865
936
  var filter = operation.filter, sorter = operation.sorter, indexFrom = operation.indexFrom, count = operation.count, data = operation.data;
866
937
  (0, assert_1.default)(!sorter, '当前update不支持sorter行为');
867
- var _a = this.analyzeJoin(entity, { filter: filter, sorter: sorter }), aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, extraWhere = _a.extraWhere, fromText = _a.from, currentNumber = _a.currentNumber;
938
+ var _a = this.analyzeJoin(entity, { filter: filter, sorter: sorter }), aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, fromText = _a.from, currentNumber = _a.currentNumber;
868
939
  var alias = aliasDict['./'];
869
940
  var updateText = '';
870
941
  for (var attr in data) {
@@ -875,7 +946,7 @@ var SqlTranslator = /** @class */ (function () {
875
946
  var value = this.translateAttrValue(attributes[attr].type, data[attr]);
876
947
  updateText += "`".concat(alias, "`.`").concat(attr, "` = ").concat(value);
877
948
  }
878
- var filterText = this.translateFilter(entity, operation, aliasDict, filterRefAlias, currentNumber, extraWhere).stmt;
949
+ var filterText = this.translateFilter(entity, filter, aliasDict, filterRefAlias, currentNumber).stmt;
879
950
  // const sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
880
951
  return this.populateUpdateStmt(updateText, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
881
952
  };
@@ -892,7 +963,7 @@ var SqlTranslator = /** @class */ (function () {
892
963
  return sql;
893
964
  };
894
965
  SqlTranslator.prototype.escapeStringValue = function (value) {
895
- var result = "'".concat(value.replace(/'/g, '\\\''), "'");
966
+ var result = "'".concat(value.replace(/'/g, '\\\'').replace(/"/g, '\\\"'), "'");
896
967
  return result;
897
968
  };
898
969
  return SqlTranslator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oak-db",
3
- "version": "2.2.10",
3
+ "version": "3.0.0",
4
4
  "description": "oak-db",
5
5
  "main": "lib/index",
6
6
  "author": {
@@ -18,7 +18,7 @@
18
18
  "lodash": "^4.17.21",
19
19
  "mysql": "^2.18.1",
20
20
  "mysql2": "^2.3.3",
21
- "oak-domain": "^2.6.9",
21
+ "oak-domain": "^3.0.0",
22
22
  "uuid": "^8.3.2"
23
23
  },
24
24
  "license": "ISC",
@@ -28,10 +28,11 @@
28
28
  "@types/mocha": "^9.1.1",
29
29
  "@types/node": "^17.0.42",
30
30
  "@types/uuid": "^8.3.4",
31
+ "cross-env": "^7.0.3",
31
32
  "mocha": "^10.0.0",
32
- "oak-general-business": "^2.5.10",
33
+ "oak-general-business": "^3.0.0",
33
34
  "ts-node": "~10.9.1",
34
35
  "tslib": "^2.4.0",
35
36
  "typescript": "~4.7.4"
36
37
  }
37
- }
38
+ }