oak-domain 4.2.1 → 4.2.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.
@@ -61,14 +61,14 @@ export declare abstract class CascadeStore<ED extends EntityDict & BaseEntityDic
61
61
  * @param filter
62
62
  * @returns
63
63
  */
64
- protected destructCascadeUpdate<T extends keyof ED, Cxt extends SyncContext<ED> | AsyncContext<ED>, OP extends OperateOption, R>(entity: T, action: ED[T]['Action'], data: ED[T]['CreateSingle']['data'] | ED[T]['Update']['data'] | ED[T]['Remove']['data'], context: Cxt, option: OP, cascadeUpdate: <T2 extends keyof ED>(entity: T2, operation: ED[T2]['Operation'], context: Cxt, option: OP) => R, filter?: ED[T]['Update']['filter']): {
64
+ protected destructCascadeUpdate<T extends keyof ED, Cxt extends SyncContext<ED> | AsyncContext<ED>, OP extends OperateOption, R>(entity: T, action: ED[T]['Action'], data: ED[T]['CreateSingle']['data'] | ED[T]['Update']['data'] | ED[T]['Remove']['data'], context: Cxt, option: OP, cascadeUpdate: <T2 extends keyof ED>(entity: T2, operation: ED[T2]['Operation'], context: Cxt, option: OP) => R, filter?: ED[T]['Update']['filter'], bornAt?: number): {
65
65
  data: Record<string, any>;
66
66
  beforeFns: (() => R)[];
67
67
  afterFns: (() => R)[];
68
68
  };
69
69
  protected preProcessDataCreated<T extends keyof ED>(entity: T, data: ED[T]['Create']['data']): void;
70
70
  protected preProcessDataUpdated(data: Record<string, any>): void;
71
- judgeRelation(entity: keyof ED, attr: string): string | 1 | 2 | string[] | 0;
71
+ judgeRelation(entity: keyof ED, attr: string): string | 1 | 2 | string[] | 0 | -1;
72
72
  /**
73
73
  * 和具体的update过程无关的例程放在这里,包括对later动作的处理、对oper的记录以及对record的收集等
74
74
  * @param entity
@@ -674,7 +674,7 @@ class CascadeStore extends RowStore_1.RowStore {
674
674
  * @param filter
675
675
  * @returns
676
676
  */
677
- destructCascadeUpdate(entity, action, data, context, option, cascadeUpdate, filter) {
677
+ destructCascadeUpdate(entity, action, data, context, option, cascadeUpdate, filter, bornAt) {
678
678
  const modiAttr = this.getSchema()[entity].toModi;
679
679
  const option2 = Object.assign({}, option);
680
680
  const opData = {};
@@ -696,7 +696,7 @@ class CascadeStore extends RowStore_1.RowStore {
696
696
  }
697
697
  }
698
698
  for (const attr in data) {
699
- const relation = (0, relation_1.judgeRelation)(this.storageSchema, entity, attr);
699
+ const relation = (0, relation_1.judgeRelation)(this.storageSchema, entity, attr, !!bornAt);
700
700
  if (relation === 1) {
701
701
  Object.assign(opData, {
702
702
  [attr]: data[attr],
@@ -814,8 +814,7 @@ class CascadeStore extends RowStore_1.RowStore {
814
814
  }
815
815
  beforeFns.push(() => cascadeUpdate.call(this, relation, operationMto, context, option2));
816
816
  }
817
- else {
818
- (0, assert_1.default)(relation instanceof Array);
817
+ else if (relation instanceof Array) {
819
818
  const [entityOtm, foreignKey] = relation;
820
819
  const otmOperations = data[attr];
821
820
  const dealWithOneToMany = (otm) => {
@@ -969,6 +968,9 @@ class CascadeStore extends RowStore_1.RowStore {
969
968
  dealWithOneToMany(otmOperations);
970
969
  }
971
970
  }
971
+ else {
972
+ console.warn(`接收到不合法的属性「${attr}」`);
973
+ }
972
974
  }
973
975
  return {
974
976
  data: opData,
@@ -1444,7 +1446,7 @@ class CascadeStore extends RowStore_1.RowStore {
1444
1446
  }
1445
1447
  }
1446
1448
  cascadeUpdate(entity, operation, context, option) {
1447
- const { action, data, filter, id } = operation;
1449
+ const { action, data, filter, id, bornAt } = operation;
1448
1450
  let opData;
1449
1451
  const wholeBeforeFns = [];
1450
1452
  const wholeAfterFns = [];
@@ -1484,21 +1486,21 @@ class CascadeStore extends RowStore_1.RowStore {
1484
1486
  * @param option
1485
1487
  */
1486
1488
  async cascadeUpdateAsync(entity, operation, context, option) {
1487
- const { action, data, filter, id } = operation;
1489
+ const { action, data, filter, id, bornAt } = operation;
1488
1490
  let opData;
1489
1491
  const wholeBeforeFns = [];
1490
1492
  const wholeAfterFns = [];
1491
1493
  if (['create', 'create-l'].includes(action) && data instanceof Array) {
1492
1494
  opData = [];
1493
1495
  for (const d of data) {
1494
- const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate(entity, action, d, context, option, this.cascadeUpdateAsync);
1496
+ const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate(entity, action, d, context, option, this.cascadeUpdateAsync, undefined, bornAt);
1495
1497
  opData.push(od);
1496
1498
  wholeBeforeFns.push(...beforeFns);
1497
1499
  wholeAfterFns.push(...afterFns);
1498
1500
  }
1499
1501
  }
1500
1502
  else {
1501
- const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate(entity, action, data, context, option, this.cascadeUpdateAsync, filter);
1503
+ const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate(entity, action, data, context, option, this.cascadeUpdateAsync, filter, bornAt);
1502
1504
  opData = od;
1503
1505
  wholeBeforeFns.push(...beforeFns);
1504
1506
  wholeAfterFns.push(...afterFns);
@@ -53,7 +53,7 @@ class RelationAuth {
53
53
  * @param destRelationId
54
54
  * @returns
55
55
  */
56
- const checkOnRelationId = (destRelationId, entity, filter) => {
56
+ const checkOnRelationId = (entity, destRelationId, filter) => {
57
57
  /**
58
58
  * 找到能创建此relation的所有父级relation,只要user和其中一个有关联即可以通过
59
59
  */
@@ -114,20 +114,48 @@ class RelationAuth {
114
114
  * @param relationFilter 限定relationId的条件
115
115
  * @param intersection 是否交集(对每个relationId都得有权限)
116
116
  * @param entityFilter 限定entity的条件
117
+ * @param entity 对应的entity
118
+ * @attention 这里为了代码复用,有可能是要通过本函数内部来查询确定entity;所以要保证,如果传入的relationFilter就可以确定relationId,则这里的entity参数必传。
117
119
  * @returns
118
120
  */
119
- const checkOnMultipleRelations = (relationFilter, intersection, entityFilter) => {
120
- const relations = context.select('relation', {
121
- data: {
122
- id: 1,
123
- entity: 1,
124
- entityId: 1,
125
- },
126
- filter: relationFilter
127
- }, { dontCollect: true });
128
- if (relations instanceof Promise) {
129
- return relations.then((rs) => {
130
- return Promise.all(rs.map(ele => checkOnRelationId(ele.id, ele.entity, entityFilter))).then((value) => {
121
+ const checkOnMultipleRelations = (relationFilter, intersection, entityFilter, entity) => {
122
+ let entity2 = entity;
123
+ const getRelationIds = () => {
124
+ const relevantIds = (0, filter_1.getRelevantIds)(relationFilter);
125
+ if (relevantIds.length > 0) {
126
+ return relevantIds;
127
+ }
128
+ const relations = context.select('relation', {
129
+ data: {
130
+ id: 1,
131
+ entity: 1,
132
+ entityId: 1,
133
+ },
134
+ filter: relationFilter
135
+ }, { dontCollect: true });
136
+ if (relations instanceof Promise) {
137
+ return relations.then((rs) => {
138
+ if (!entity2) {
139
+ entity2 = rs[0]?.entity;
140
+ }
141
+ else {
142
+ (0, assert_1.default)(entity2 === rs[0]?.entity);
143
+ }
144
+ return rs.map(ele => ele.id);
145
+ });
146
+ }
147
+ if (!entity2) {
148
+ entity2 = relations[0]?.entity;
149
+ }
150
+ else {
151
+ (0, assert_1.default)(entity2 === relations[0]?.entity);
152
+ }
153
+ return relations.map(ele => ele.id);
154
+ };
155
+ const relationIds = getRelationIds();
156
+ if (relationIds instanceof Promise) {
157
+ return relationIds.then((ids) => {
158
+ return Promise.all(ids.map(ele => checkOnRelationId(entity2, ele, entityFilter))).then((value) => {
131
159
  if (intersection) {
132
160
  return !(value.includes(false));
133
161
  }
@@ -135,7 +163,7 @@ class RelationAuth {
135
163
  });
136
164
  });
137
165
  }
138
- const value = relations.map(ele => checkOnRelationId(ele.id, ele.entity, entityFilter));
166
+ const value = relationIds.map(ele => checkOnRelationId(entity2, ele, entityFilter));
139
167
  if (intersection) {
140
168
  return !(value.includes(false));
141
169
  }
@@ -156,12 +184,14 @@ class RelationAuth {
156
184
  }
157
185
  if (relationId) {
158
186
  // 如果指定relation,则测试该relation上是否可行
159
- (0, assert_1.default)(typeof relationId === 'string');
160
- return checkOnRelationId(relationId, entity, entityFilter);
187
+ // 目前可能会有多个relationIds传入(userEntityGrant做测试),但一定是可以确定的relationId集合
188
+ return checkOnMultipleRelations({ id: relationId }, true, entityFilter, entity);
161
189
  }
162
190
  else {
163
191
  // 否则为测试“能否”有权限管理的资格,此时只要有一个就可以
164
192
  // 这是为上层的menu所有,真正的创建不可能走到这里
193
+ // bug fixed,目前框架不支持entityId为null,所以这里暂时只支持entityId一种方式的测试
194
+ (0, assert_1.default)(entityId);
165
195
  return checkOnMultipleRelations({
166
196
  entity,
167
197
  $or: [
@@ -171,10 +201,10 @@ class RelationAuth {
171
201
  },
172
202
  },
173
203
  {
174
- [entity]: entityFilter,
204
+ entityId,
175
205
  }
176
206
  ]
177
- }, false, entityFilter);
207
+ }, false, entityFilter, entity);
178
208
  }
179
209
  }
180
210
  else {
@@ -184,7 +214,7 @@ class RelationAuth {
184
214
  userRelation$relation: filter,
185
215
  }, false, {
186
216
  userRelation$entity: filter,
187
- });
217
+ }, filter.entity);
188
218
  }
189
219
  }
190
220
  checkOperateSpecialEntities2(entity2, action, filter, context) {
@@ -9,4 +9,4 @@ import { StorageSchema } from "../types/Storage";
9
9
  * @param row
10
10
  * @returns
11
11
  */
12
- export declare function judgeRelation<ED extends EntityDict & BaseEntityDict>(schema: StorageSchema<ED>, entity: keyof ED, attr: string): string | 1 | 2 | string[] | 0;
12
+ export declare function judgeRelation<ED extends EntityDict & BaseEntityDict>(schema: StorageSchema<ED>, entity: keyof ED, attr: string, allowUnrecoganized?: boolean): string | 1 | 2 | string[] | 0 | -1;
@@ -13,7 +13,7 @@ const Entity_1 = require("../types/Entity");
13
13
  * @param row
14
14
  * @returns
15
15
  */
16
- function judgeRelation(schema, entity, attr) {
16
+ function judgeRelation(schema, entity, attr, allowUnrecoganized) {
17
17
  const { [entity]: { attributes } } = schema;
18
18
  if (attr.startsWith(Demand_1.EXPRESSION_PREFIX) || attr.startsWith('#')) {
19
19
  // 表达式属性或者metadata
@@ -60,8 +60,15 @@ function judgeRelation(schema, entity, attr) {
60
60
  return 2;
61
61
  }
62
62
  else {
63
- (0, assert_1.default)(Entity_1.initinctiveAttributes.includes(attr), `${entity}对象中的${attr}属性找不到`);
64
- return 1;
63
+ if (Entity_1.initinctiveAttributes.includes(attr)) {
64
+ return 1;
65
+ }
66
+ else if (allowUnrecoganized) {
67
+ return -1;
68
+ }
69
+ else {
70
+ throw new Error(`${entity}对象中的${attr}属性找不到`);
71
+ }
65
72
  }
66
73
  }
67
74
  exports.judgeRelation = judgeRelation;
@@ -17,26 +17,47 @@ export type SelfEncryptInfo = {
17
17
  privateKey: string;
18
18
  algorithm: Algorithm;
19
19
  };
20
- export interface SyncEntityDef<ED extends EntityDict & BaseEntityDict, T extends keyof ED> {
20
+ export interface PullEntityDef<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> {
21
+ direction: 'pull';
21
22
  entity: T;
22
23
  path: string;
23
24
  recursive?: boolean;
24
25
  relationName?: string;
25
- direction: 'pull' | 'push' | 'bio';
26
+ process?: <A extends ED[T]['Action']>(action: A, data: ED[T]['Operation']['data'], context: Cxt) => Promise<void>;
26
27
  }
27
- export interface SyncRemoteConfigBase<ED extends EntityDict & BaseEntityDict> {
28
+ export interface PushEntityDef<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>> {
29
+ direction: 'push';
30
+ entity: T;
31
+ path: string;
32
+ recursive?: boolean;
33
+ relationName?: string;
34
+ actions?: ED[T]['Action'][];
35
+ onSynchronized?: (result: {
36
+ action: ED[T]['Action'];
37
+ data: ED[T]['Operation']['data'];
38
+ result: Array<{
39
+ userId: string;
40
+ rowIds: string[];
41
+ error?: Error;
42
+ }>;
43
+ }, context: Cxt) => Promise<void>;
44
+ }
45
+ export interface SyncRemoteConfigBase<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> {
28
46
  entity: keyof ED;
47
+ entitySelf?: keyof ED;
29
48
  endpoint?: string;
30
49
  pathToUser?: string;
31
50
  relationName?: string;
32
- syncEntities: Array<SyncEntityDef<ED, keyof ED>>;
51
+ pushEntities?: Array<PushEntityDef<ED, keyof ED, Cxt>>;
52
+ pullEntities?: Array<PullEntityDef<ED, keyof ED, Cxt>>;
33
53
  }
34
- interface SyncRemoteConfig<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends SyncRemoteConfigBase<ED> {
54
+ interface SyncRemoteConfig<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends SyncRemoteConfigBase<ED, Cxt> {
35
55
  getPushInfo: (userId: string, context: Cxt) => Promise<RemotePushInfo>;
36
56
  getPullInfo: (id: string, context: Cxt) => Promise<RemotePullInfo>;
37
57
  }
38
58
  export interface SyncSelfConfigBase<ED extends EntityDict & BaseEntityDict> {
39
59
  endpoint?: string;
60
+ entitySelf: keyof ED;
40
61
  }
41
62
  interface SyncSelfConfig<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>> extends SyncSelfConfigBase<ED> {
42
63
  getSelfEncryptInfo: (context: Cxt) => Promise<SelfEncryptInfo>;
package/lib/types/Sync.js CHANGED
@@ -6,3 +6,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  ;
7
7
  ;
8
8
  ;
9
+ ;
@@ -11,7 +11,7 @@ import { EntityDict } from "../types/Entity";
11
11
  */
12
12
  export declare function destructRelationPath<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(schema: StorageSchema<ED>, entity: T, path: string, relationFilter: ED['userRelation']['Selection']['filter'], recursive?: boolean): {
13
13
  projection: ED[T]['Selection']['data'];
14
- getData: (d: Partial<ED[T]['Schema']>) => ED['userRelation']['Schema'][];
14
+ getData: (d: Partial<ED[T]['Schema']>) => ED['userRelation']['Schema'][] | undefined;
15
15
  };
16
16
  /**
17
17
  * 根据entity的相对path,找到对应的根结点对象上的直接userId
@@ -27,5 +27,5 @@ export declare function destructDirectPath<ED extends EntityDict & BaseEntityDic
27
27
  entity: keyof ED;
28
28
  entityId: string;
29
29
  userId: string;
30
- }[];
30
+ }[] | undefined;
31
31
  };
@@ -59,7 +59,7 @@ function destructRelationPath(schema, entity, path, relationFilter, recursive) {
59
59
  userId: 1,
60
60
  },
61
61
  filter: relationFilter,
62
- }
62
+ } // as ED['userRelation']['Selection']
63
63
  },
64
64
  getData: (d) => {
65
65
  return d.userRelation$entity;
@@ -100,7 +100,7 @@ function destructRelationPath(schema, entity, path, relationFilter, recursive) {
100
100
  data: projection,
101
101
  },
102
102
  },
103
- getData: (d) => d[attr] && d[attr].map((ele) => getData(ele)),
103
+ getData: (d) => d[attr] && d[attr].map(ele => getData(ele)).flat().filter(ele => !!ele),
104
104
  };
105
105
  }
106
106
  };
@@ -133,11 +133,11 @@ function destructDirectPath(schema, entity, path, recursive) {
133
133
  },
134
134
  getData: (d) => {
135
135
  if (d) {
136
- return {
137
- entity: e,
138
- entityId: d.id,
139
- userId: d.entityId,
140
- };
136
+ return [{
137
+ entity: e,
138
+ entityId: d.id,
139
+ userId: d.entityId,
140
+ }];
141
141
  }
142
142
  },
143
143
  };
@@ -151,11 +151,11 @@ function destructDirectPath(schema, entity, path, recursive) {
151
151
  },
152
152
  getData: (d) => {
153
153
  if (d) {
154
- return {
155
- entity: e,
156
- entityId: d.id,
157
- userId: d[`${attr}Id`]
158
- };
154
+ return [{
155
+ entity: e,
156
+ entityId: d.id,
157
+ userId: d[`${attr}Id`],
158
+ }];
159
159
  }
160
160
  },
161
161
  };
@@ -193,7 +193,7 @@ function destructDirectPath(schema, entity, path, recursive) {
193
193
  data: projection,
194
194
  },
195
195
  },
196
- getData: (d) => d[attr] && d[attr].map((ele) => getData(ele)),
196
+ getData: (d) => d[attr] && d[attr].map(ele => getData(ele)).flat().filter(ele => !!ele),
197
197
  };
198
198
  }
199
199
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oak-domain",
3
- "version": "4.2.1",
3
+ "version": "4.2.2",
4
4
  "author": {
5
5
  "name": "XuChang"
6
6
  },