oak-domain 5.0.18 → 5.0.19

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.
@@ -100,8 +100,9 @@ function makeWebAllRouters(namespaceDir, projectDir, routerFileDir) {
100
100
  const nsIndexJsonFile = (0, path_1.join)(namespaceDir, ns, 'index.json');
101
101
  let path2 = `/${ns}`;
102
102
  let notFound2 = '', first2 = '';
103
+ let params2 = {};
103
104
  if ((0, fs_extra_1.existsSync)(nsIndexJsonFile)) {
104
- const { path, notFound, first } = require(nsIndexJsonFile);
105
+ const { path, notFound, first, params } = require(nsIndexJsonFile);
105
106
  if (path) {
106
107
  path2 = path.replace(/\\/g, '/');
107
108
  }
@@ -114,11 +115,19 @@ function makeWebAllRouters(namespaceDir, projectDir, routerFileDir) {
114
115
  first2 = first2.slice(1);
115
116
  }
116
117
  }
118
+ if (params) {
119
+ params2 = params;
120
+ }
117
121
  }
118
122
  let firstPage;
119
123
  const children = Object.values(pages).filter((ele) => ele.hasWeb).map(({ path, oakDisablePulldownRefresh }) => {
124
+ let path2 = path;
125
+ if (params2[path]) {
126
+ // 如果有参数,接在path后面
127
+ path2 += `/:${params2[path]}`;
128
+ }
120
129
  const properties = [
121
- factory.createPropertyAssignment('path', factory.createStringLiteral(path)),
130
+ factory.createPropertyAssignment('path', factory.createStringLiteral(path2)),
122
131
  factory.createPropertyAssignment('namespace', factory.createStringLiteral(ns)),
123
132
  factory.createPropertyAssignment('meta', factory.createObjectLiteralExpression([
124
133
  factory.createPropertyAssignment('oakDisablePulldownRefresh', oakDisablePulldownRefresh ? factory.createTrue() : factory.createFalse())
@@ -39,4 +39,12 @@ export declare class TriggerExecutor<ED extends EntityDict & BaseEntityDict, Cxt
39
39
  action: 'select';
40
40
  }, context: Cxt, option: OperateOption | SelectOption, result?: Partial<ED[T]['Schema']>[]): Promise<void> | void;
41
41
  checkpoint(timestamp: number): Promise<number>;
42
+ /**
43
+ * 由外部来控制进行按volatileTrigger逐个进行checkpoint
44
+ * @param name
45
+ * @param timestamp
46
+ * @param instanceCount
47
+ * @param instanceId
48
+ */
49
+ independentCheckPoint(name: string, timestamp: number, instanceCount?: number, instanceId?: number): Promise<number>;
42
50
  }
@@ -49,8 +49,12 @@ class TriggerExecutor {
49
49
  await context.commit();
50
50
  }
51
51
  catch (err) {
52
- await context.rollback();
53
- if (!(err instanceof types_1.OakMakeSureByMySelfException)) {
52
+ if (!(err instanceof types_1.OakPartialSuccess)) {
53
+ await context.rollback();
54
+ this.logger.error('error on volatile trigger', entity, trigger.name, ids.join(','), err);
55
+ }
56
+ else {
57
+ await context.commit();
54
58
  this.logger.error('error on volatile trigger', entity, trigger.name, ids.join(','), err);
55
59
  }
56
60
  // throw err;
@@ -363,6 +367,12 @@ class TriggerExecutor {
363
367
  filter: {
364
368
  id: {
365
369
  $in: ids,
370
+ },
371
+ [Entity_1.TriggerDataAttribute]: {
372
+ $exists: true,
373
+ },
374
+ [Entity_1.TriggerUuidAttribute]: {
375
+ $exists: true,
366
376
  }
367
377
  }
368
378
  }, { includedDeleted: true, blockTrigger: true });
@@ -473,10 +483,6 @@ class TriggerExecutor {
473
483
  async checkpoint(timestamp) {
474
484
  let result = 0;
475
485
  for (const entity of this.volatileEntities) {
476
- if (entity === 'oper') {
477
- // oper上的跨事务同步是系统synchronizer统一处理
478
- continue;
479
- }
480
486
  const filter = {
481
487
  [Entity_1.TriggerUuidAttribute]: {
482
488
  $exists: true,
@@ -486,12 +492,6 @@ class TriggerExecutor {
486
492
  }
487
493
  };
488
494
  const context = this.contextBuilder();
489
- if (context.clusterInfo?.usingCluster) {
490
- const { instanceCount, instanceId } = context.clusterInfo;
491
- filter.$$seq$$ = {
492
- $mod: [instanceCount, instanceId],
493
- };
494
- }
495
495
  await context.begin();
496
496
  try {
497
497
  const rows = await context.select(entity, {
@@ -532,15 +532,108 @@ class TriggerExecutor {
532
532
  }
533
533
  }
534
534
  await context.commit();
535
+ result += rows.length;
535
536
  }
536
537
  catch (err) {
537
- await context.rollback();
538
- if (!(err instanceof types_1.OakMakeSureByMySelfException)) {
539
- this.logger.error(`执行checkpoint时出错,对象是「${entity}」,异常是`, err);
538
+ if (!(err instanceof types_1.OakPartialSuccess)) {
539
+ await context.rollback();
540
+ this.logger.error(`error in checkpoint on entity 「${entity}」`, err);
541
+ }
542
+ else {
543
+ await context.commit();
544
+ this.logger.error(`error in checkpoint on entity 「${entity}」`, err);
540
545
  }
541
546
  }
542
547
  }
543
548
  return result;
544
549
  }
550
+ /**
551
+ * 由外部来控制进行按volatileTrigger逐个进行checkpoint
552
+ * @param name
553
+ * @param timestamp
554
+ * @param instanceCount
555
+ * @param instanceId
556
+ */
557
+ async independentCheckPoint(name, timestamp, instanceCount, instanceId) {
558
+ const trigger = this.triggerNameMap[name];
559
+ (0, assert_1.default)(trigger && trigger.when === 'commit');
560
+ const { fn, entity, grouped } = trigger;
561
+ const filter = {
562
+ [Entity_1.TriggerDataAttribute]: {
563
+ name,
564
+ },
565
+ [Entity_1.TriggerUuidAttribute]: {
566
+ $exists: true,
567
+ },
568
+ [Entity_1.UpdateAtAttribute]: {
569
+ $lt: timestamp,
570
+ },
571
+ };
572
+ if (instanceCount) {
573
+ filter.$$seq$$ = {
574
+ $mod: [instanceCount, instanceId]
575
+ };
576
+ }
577
+ const context = this.contextBuilder();
578
+ await context.begin();
579
+ try {
580
+ const rows = await context.select(entity, {
581
+ data: {
582
+ id: 1,
583
+ },
584
+ filter,
585
+ }, {
586
+ includedDeleted: true,
587
+ dontCollect: true,
588
+ });
589
+ if (rows.length > 0) {
590
+ // 要用id来再锁一次,不然会锁住filter的范围,影响并发性
591
+ // by Xc 20240314,在haina-busi和haina-cn数据sync过程中发现这个问题
592
+ const rows2 = await context.select(entity, {
593
+ data: {
594
+ id: 1,
595
+ [Entity_1.TriggerDataAttribute]: 1,
596
+ [Entity_1.TriggerUuidAttribute]: 1,
597
+ },
598
+ filter: {
599
+ id: {
600
+ $in: rows.map(ele => ele.id),
601
+ },
602
+ },
603
+ }, {
604
+ includedDeleted: true,
605
+ dontCollect: true,
606
+ forUpdate: 'skip locked', // 如果加不上锁就下次再处理,或者有可能应用自己在处理
607
+ });
608
+ if (grouped) {
609
+ // grouped不需要上下文了吧,内部一定会用root
610
+ await this.execVolatileTrigger(entity, name, rows.map(ele => ele.id), context, {});
611
+ }
612
+ else {
613
+ const groupedRowDict = (0, lodash_1.groupBy)(rows2, Entity_1.TriggerUuidAttribute);
614
+ for (const uuid in groupedRowDict) {
615
+ const rs = groupedRowDict[uuid];
616
+ const { [Entity_1.TriggerDataAttribute]: triggerData } = rs[0];
617
+ const { cxtStr, option } = triggerData;
618
+ await context.initialize(JSON.parse(cxtStr), true);
619
+ await this.execVolatileTrigger(entity, name, rs.map(ele => ele.id), context, option);
620
+ }
621
+ }
622
+ }
623
+ await context.commit();
624
+ return rows.length;
625
+ }
626
+ catch (err) {
627
+ if (!(err instanceof types_1.OakPartialSuccess)) {
628
+ await context.rollback();
629
+ this.logger.error('error on volatile trigger', entity, trigger.name, err);
630
+ }
631
+ else {
632
+ await context.commit();
633
+ this.logger.error('error on volatile trigger', entity, trigger.name, err);
634
+ }
635
+ return 0;
636
+ }
637
+ }
545
638
  }
546
639
  exports.TriggerExecutor = TriggerExecutor;
@@ -19,7 +19,7 @@ export declare class OakException<ED extends EntityDict & BaseEntityDict> extend
19
19
  tag2?: boolean;
20
20
  tag3?: any;
21
21
  }
22
- export declare class OakMakeSureByMySelfException<ED extends EntityDict & BaseEntityDict> extends OakException<ED> {
22
+ export declare class OakPartialSuccess<ED extends EntityDict & BaseEntityDict> extends OakException<ED> {
23
23
  }
24
24
  export declare class OakDataException<ED extends EntityDict & BaseEntityDict> extends OakException<ED> {
25
25
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeException = exports.OakExternalException = exports.OakPreConditionUnsetException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserInvisibleException = exports.OakUserUnpermittedException = exports.OakAttrCantUpdateException = exports.OakAttrNotNullException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakServerProxyException = exports.OakNetworkException = exports.OakImportDataParseException = exports.OakUniqueViolationException = exports.OakUserException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakNoRelationDefException = exports.OakDataException = exports.OakMakeSureByMySelfException = exports.OakException = void 0;
3
+ exports.makeException = exports.OakExternalException = exports.OakPreConditionUnsetException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserInvisibleException = exports.OakUserUnpermittedException = exports.OakAttrCantUpdateException = exports.OakAttrNotNullException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakServerProxyException = exports.OakNetworkException = exports.OakImportDataParseException = exports.OakUniqueViolationException = exports.OakUserException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakNoRelationDefException = exports.OakDataException = exports.OakPartialSuccess = exports.OakException = void 0;
4
4
  const relation_1 = require("../store/relation");
5
5
  const lodash_1 = require("../utils/lodash");
6
6
  class OakException extends Error {
@@ -90,10 +90,10 @@ class OakException extends Error {
90
90
  tag3;
91
91
  }
92
92
  exports.OakException = OakException;
93
- // 这个异常表示模块自己处理跨事务一致性,框架pass(在分布式数据传递时会用到)
94
- class OakMakeSureByMySelfException extends OakException {
93
+ // 这个异常表示事务虽然没有完全成功,但是仍然应该提交并抛出异常(在分布式数据传递时会用到)
94
+ class OakPartialSuccess extends OakException {
95
95
  }
96
- exports.OakMakeSureByMySelfException = OakMakeSureByMySelfException;
96
+ exports.OakPartialSuccess = OakPartialSuccess;
97
97
  class OakDataException extends OakException {
98
98
  }
99
99
  exports.OakDataException = OakDataException;
@@ -12,6 +12,7 @@ export type FreeTimer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
12
12
  name: string;
13
13
  cron: RecurrenceRule | RecurrenceSpecDateRange | RecurrenceSpecObjLit | Date | string | number;
14
14
  timer: FreeOperateFn<ED, Cxt>;
15
+ singleton?: true;
15
16
  };
16
17
  export type Routine<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> = FreeRoutine<ED, Cxt> | Watcher<ED, T, Cxt>;
17
18
  export type Timer<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> = FreeTimer<ED, Cxt> | Watcher<ED, T, Cxt> & {
@@ -39,6 +39,8 @@ interface TriggerCrossTxn<ED extends EntityDict, Cxt extends AsyncContext<ED> |
39
39
  when: 'commit';
40
40
  strict?: 'takeEasy' | 'makeSure';
41
41
  cs?: true;
42
+ singleton?: true;
43
+ grouped?: true;
42
44
  fn: (event: {
43
45
  ids: string[];
44
46
  }, context: Cxt, option: OperateOption) => Promise<((context: Cxt, option: OperateOption) => Promise<any>) | void>;
@@ -8,6 +8,7 @@ export interface BBWatcher<ED extends EntityDict, T extends keyof ED> {
8
8
  filter: ED[T]['Selection']['filter'] | (() => ED[T]['Selection']['filter']);
9
9
  action: Omit<ED[T]['Action'], 'create' | ReadOnlyAction>;
10
10
  actionData: ActionData<ED, T> | (() => Promise<ActionData<ED, T>>);
11
+ singleton?: true;
11
12
  }
12
13
  export interface WBWatcher<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> {
13
14
  name: string;
@@ -15,6 +16,7 @@ export interface WBWatcher<ED extends EntityDict, T extends keyof ED, Cxt extend
15
16
  filter: ED[T]['Selection']['filter'] | (() => Promise<ED[T]['Selection']['filter']>);
16
17
  projection: ED[T]['Selection']['data'] | (() => Promise<ED[T]['Selection']['data']>);
17
18
  fn: (context: Cxt, data: Partial<ED[T]['Schema']>[]) => Promise<OperationResult<ED>>;
19
+ singleton?: true;
18
20
  }
19
21
  export type Watcher<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> = BBWatcher<ED, T> | WBWatcher<ED, T, Cxt>;
20
22
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oak-domain",
3
- "version": "5.0.18",
3
+ "version": "5.0.19",
4
4
  "author": {
5
5
  "name": "XuChang"
6
6
  },
@@ -1,26 +1,26 @@
1
- import { String } from '../types/DataType';
2
- import { EntityShape } from '../types/Entity';
3
- import { Schema as Modi } from './Modi';
4
- import { EntityDesc } from '../types/EntityDesc';
5
-
6
- export interface Schema extends EntityShape {
7
- modi: Modi,
8
- entity: String<32>;
9
- entityId: String<64>;
10
- };
11
-
12
- const entityDesc: EntityDesc<Schema> = {
13
- locales: {
14
- zh_CN: {
15
- name: '更新对象连接',
16
- attr: {
17
- modi: '更新',
18
- entity: '关联对象',
19
- entityId: '关联对象id',
20
- },
21
- },
22
- },
23
- configuration: {
24
- actionType: 'appendOnly',
25
- }
26
- };
1
+ import { String } from '../types/DataType';
2
+ import { EntityShape } from '../types/Entity';
3
+ import { Schema as Modi } from './Modi';
4
+ import { EntityDesc } from '../types/EntityDesc';
5
+
6
+ export interface Schema extends EntityShape {
7
+ modi: Modi,
8
+ entity: String<32>;
9
+ entityId: String<64>;
10
+ };
11
+
12
+ const entityDesc: EntityDesc<Schema> = {
13
+ locales: {
14
+ zh_CN: {
15
+ name: '更新对象连接',
16
+ attr: {
17
+ modi: '更新',
18
+ entity: '关联对象',
19
+ entityId: '关联对象id',
20
+ },
21
+ },
22
+ },
23
+ configuration: {
24
+ actionType: 'appendOnly',
25
+ }
26
+ };
@@ -1,27 +1,27 @@
1
- import { String } from '../types/DataType';
2
- import { EntityShape, Configuration } from '../types/Entity';
3
- import { LocaleDef } from '../types/Locale';
4
- import { Schema as Oper } from './Oper';
5
- import { EntityDesc } from '../types/EntityDesc';
6
-
7
- export interface Schema extends EntityShape {
8
- oper: Oper,
9
- entity: String<32>;
10
- entityId: String<64>;
11
- };
12
-
13
- const entityDesc: EntityDesc<Schema> = {
14
- locales: {
15
- zh_CN: {
16
- name: '操作对象连接',
17
- attr: {
18
- oper: '操作',
19
- entity: '关联对象',
20
- entityId: '关联对象id',
21
- },
22
- },
23
- },
24
- configuration: {
25
- actionType: 'appendOnly',
26
- }
27
- };
1
+ import { String } from '../types/DataType';
2
+ import { EntityShape, Configuration } from '../types/Entity';
3
+ import { LocaleDef } from '../types/Locale';
4
+ import { Schema as Oper } from './Oper';
5
+ import { EntityDesc } from '../types/EntityDesc';
6
+
7
+ export interface Schema extends EntityShape {
8
+ oper: Oper,
9
+ entity: String<32>;
10
+ entityId: String<64>;
11
+ };
12
+
13
+ const entityDesc: EntityDesc<Schema> = {
14
+ locales: {
15
+ zh_CN: {
16
+ name: '操作对象连接',
17
+ attr: {
18
+ oper: '操作',
19
+ entity: '关联对象',
20
+ entityId: '关联对象id',
21
+ },
22
+ },
23
+ },
24
+ configuration: {
25
+ actionType: 'appendOnly',
26
+ }
27
+ };
@@ -1,43 +1,43 @@
1
- import { String } from '../types/DataType';
2
- import { EntityShape } from '../types/Entity';
3
- import { EntityDesc } from '../types/EntityDesc';
4
-
5
- export interface Schema extends EntityShape {
6
- entity: String<32>;
7
- entityId?: String<64>; // 可以为空
8
- name?: String<32>;
9
- display?: String<32>;
10
- };
11
-
12
- const entityDesc: EntityDesc<Schema> = {
13
- locales: {
14
- zh_CN: {
15
- name: '用户授权',
16
- attr: {
17
- name: '关系',
18
- entity: '目标对象',
19
- entityId: '目标对象id',
20
- display: '显示值',
21
- },
22
- },
23
- },
24
- indexes: [
25
- {
26
- name: 'index_targetEntity_entityId_name',
27
- attributes: [
28
- {
29
- name: 'entity',
30
- },
31
- {
32
- name: 'entityId',
33
- },
34
- {
35
- name: 'name',
36
- }
37
- ],
38
- config: {
39
- unique: true,
40
- },
41
- },
42
- ]
43
- };
1
+ import { String } from '../types/DataType';
2
+ import { EntityShape } from '../types/Entity';
3
+ import { EntityDesc } from '../types/EntityDesc';
4
+
5
+ export interface Schema extends EntityShape {
6
+ entity: String<32>;
7
+ entityId?: String<64>; // 可以为空
8
+ name?: String<32>;
9
+ display?: String<32>;
10
+ };
11
+
12
+ const entityDesc: EntityDesc<Schema> = {
13
+ locales: {
14
+ zh_CN: {
15
+ name: '用户授权',
16
+ attr: {
17
+ name: '关系',
18
+ entity: '目标对象',
19
+ entityId: '目标对象id',
20
+ display: '显示值',
21
+ },
22
+ },
23
+ },
24
+ indexes: [
25
+ {
26
+ name: 'index_targetEntity_entityId_name',
27
+ attributes: [
28
+ {
29
+ name: 'entity',
30
+ },
31
+ {
32
+ name: 'entityId',
33
+ },
34
+ {
35
+ name: 'name',
36
+ }
37
+ ],
38
+ config: {
39
+ unique: true,
40
+ },
41
+ },
42
+ ]
43
+ };
@@ -1,30 +1,30 @@
1
- import { String } from '../types/DataType';
2
- import { EntityShape } from '../types/Entity';
3
- import { EntityDesc } from '../types/EntityDesc';
4
- import { Schema as UserEntityGrant } from './UserEntityGrant';
5
- import { Schema as User } from './User';
6
- import { Schema as Relation } from './Relation';
7
- import { Schema as UserRelation } from './UserRelation';
8
-
9
- export interface Schema extends EntityShape {
10
- ueg: UserEntityGrant;
11
- user: User;
12
- relation: Relation;
13
- claimEntityId: String<64>;
14
- userRelation: UserRelation;
15
- };
16
-
17
- const entityDesc: EntityDesc<Schema, ''> = {
18
- locales: {
19
- zh_CN: {
20
- name: '用户授权领取',
21
- attr: {
22
- ueg: '授权',
23
- user: '用户',
24
- relation: '关系',
25
- claimEntityId: '对象Id',
26
- userRelation: '用户关系',
27
- },
28
- },
29
- },
1
+ import { String } from '../types/DataType';
2
+ import { EntityShape } from '../types/Entity';
3
+ import { EntityDesc } from '../types/EntityDesc';
4
+ import { Schema as UserEntityGrant } from './UserEntityGrant';
5
+ import { Schema as User } from './User';
6
+ import { Schema as Relation } from './Relation';
7
+ import { Schema as UserRelation } from './UserRelation';
8
+
9
+ export interface Schema extends EntityShape {
10
+ ueg: UserEntityGrant;
11
+ user: User;
12
+ relation: Relation;
13
+ claimEntityId: String<64>;
14
+ userRelation: UserRelation;
15
+ };
16
+
17
+ const entityDesc: EntityDesc<Schema, ''> = {
18
+ locales: {
19
+ zh_CN: {
20
+ name: '用户授权领取',
21
+ attr: {
22
+ ueg: '授权',
23
+ user: '用户',
24
+ relation: '关系',
25
+ claimEntityId: '对象Id',
26
+ userRelation: '用户关系',
27
+ },
28
+ },
29
+ },
30
30
  };
@@ -1,24 +1,24 @@
1
- import { String } from '../types/DataType';
2
- import { EntityShape } from '../types/Entity';
3
- import { EntityDesc } from '../types/EntityDesc';
4
-
5
- type RelationIds = string[];
6
-
7
- export interface Schema extends EntityShape {
8
- relationEntity: String<32>;
9
- relationEntityFilter: Object;
10
- relationIds: RelationIds;
11
- };
12
-
13
- const entityDesc: EntityDesc<Schema, ''> = {
14
- locales: {
15
- zh_CN: {
16
- name: '用户授权',
17
- attr: {
18
- relationIds: '关系',
19
- relationEntity: '关联对象',
20
- relationEntityFilter: '对象限定条件',
21
- },
22
- },
23
- },
24
- };
1
+ import { String } from '../types/DataType';
2
+ import { EntityShape } from '../types/Entity';
3
+ import { EntityDesc } from '../types/EntityDesc';
4
+
5
+ type RelationIds = string[];
6
+
7
+ export interface Schema extends EntityShape {
8
+ relationEntity: String<32>;
9
+ relationEntityFilter: Object;
10
+ relationIds: RelationIds;
11
+ };
12
+
13
+ const entityDesc: EntityDesc<Schema, ''> = {
14
+ locales: {
15
+ zh_CN: {
16
+ name: '用户授权',
17
+ attr: {
18
+ relationIds: '关系',
19
+ relationEntity: '关联对象',
20
+ relationEntityFilter: '对象限定条件',
21
+ },
22
+ },
23
+ },
24
+ };
@@ -1,50 +1,50 @@
1
- import { String } from '../types/DataType';
2
- import { LocaleDef } from '../types/Locale';
3
- import { EntityShape } from '../types/Entity';
4
- import { Index } from '../types/Storage';
5
- import { Schema as User } from './User';
6
- import { Schema as Relation } from './Relation';
7
- import { EntityDesc } from '../types/EntityDesc';
8
-
9
- export interface Schema extends EntityShape {
10
- user: User;
11
- relation: Relation;
12
- entity: String<32>;
13
- entityId: String<64>;
14
- };
15
-
16
- const entityDesc: EntityDesc<Schema> = {
17
- locales: {
18
- zh_CN: {
19
- name: '用户对象关系',
20
- attr: {
21
- user: '关系',
22
- relation: '目标关系',
23
- entity: '目标对象',
24
- entityId: '目标对象ID',
25
- },
26
- },
27
- },
28
- indexes: [
29
- {
30
- name: 'index_user_entity_entityId_relation',
31
- attributes: [
32
- {
33
- name: 'user',
34
- },
35
- {
36
- name: 'entity',
37
- },
38
- {
39
- name: 'entityId',
40
- },
41
- {
42
- name: 'relation',
43
- },
44
- ],
45
- config: {
46
- unique: true,
47
- },
48
- },
49
- ]
50
- };
1
+ import { String } from '../types/DataType';
2
+ import { LocaleDef } from '../types/Locale';
3
+ import { EntityShape } from '../types/Entity';
4
+ import { Index } from '../types/Storage';
5
+ import { Schema as User } from './User';
6
+ import { Schema as Relation } from './Relation';
7
+ import { EntityDesc } from '../types/EntityDesc';
8
+
9
+ export interface Schema extends EntityShape {
10
+ user: User;
11
+ relation: Relation;
12
+ entity: String<32>;
13
+ entityId: String<64>;
14
+ };
15
+
16
+ const entityDesc: EntityDesc<Schema> = {
17
+ locales: {
18
+ zh_CN: {
19
+ name: '用户对象关系',
20
+ attr: {
21
+ user: '关系',
22
+ relation: '目标关系',
23
+ entity: '目标对象',
24
+ entityId: '目标对象ID',
25
+ },
26
+ },
27
+ },
28
+ indexes: [
29
+ {
30
+ name: 'index_user_entity_entityId_relation',
31
+ attributes: [
32
+ {
33
+ name: 'user',
34
+ },
35
+ {
36
+ name: 'entity',
37
+ },
38
+ {
39
+ name: 'entityId',
40
+ },
41
+ {
42
+ name: 'relation',
43
+ },
44
+ ],
45
+ config: {
46
+ unique: true,
47
+ },
48
+ },
49
+ ]
50
+ };