oak-domain 5.1.13 → 5.1.14

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.
@@ -69,6 +69,7 @@ export declare abstract class CascadeStore<ED extends EntityDict & BaseEntityDic
69
69
  protected preProcessDataCreated<T extends keyof ED>(entity: T, data: ED[T]['Create']['data']): void;
70
70
  protected preProcessDataUpdated(action: string, data: Record<string, any>, async?: true): void;
71
71
  judgeRelation(entity: keyof ED, attr: string): string | 1 | 2 | string[] | 0 | -1;
72
+ private tryMergeModi;
72
73
  /**
73
74
  * 和具体的update过程无关的例程放在这里,包括对later动作的处理、对oper的记录以及对record的收集等
74
75
  * @param entity
@@ -1051,6 +1051,118 @@ class CascadeStore extends RowStore_1.RowStore {
1051
1051
  judgeRelation(entity, attr) {
1052
1052
  return (0, relation_1.judgeRelation)(this.storageSchema, entity, attr);
1053
1053
  }
1054
+ async tryMergeModi(entity, operation, context, ids, option) {
1055
+ const { action, data, filter, id: operId } = operation;
1056
+ const [upsertModi] = await this.selectAbjointRowAsync('modi', {
1057
+ data: {
1058
+ id: 1,
1059
+ data: 1,
1060
+ action: 1,
1061
+ },
1062
+ filter: {
1063
+ targetEntity: entity,
1064
+ iState: 'active',
1065
+ filter: ids.length > 0 ? {
1066
+ id: {
1067
+ $in: ids,
1068
+ },
1069
+ } : {
1070
+ id: ids[0],
1071
+ },
1072
+ },
1073
+ sorter: [
1074
+ {
1075
+ $attr: {
1076
+ $$createAt$$: 1,
1077
+ },
1078
+ $direction: 'desc',
1079
+ }
1080
+ ],
1081
+ indexFrom: 0,
1082
+ count: 1,
1083
+ }, context, option);
1084
+ if (upsertModi) {
1085
+ const { data: data2, id: id2, action: action2 } = upsertModi;
1086
+ if (action === 'remove') {
1087
+ // 之前的都不做数
1088
+ if (action2 === 'create') {
1089
+ // 对冲掉
1090
+ return {
1091
+ id: await (0, uuid_1.generateNewIdAsync)(),
1092
+ action: 'remove',
1093
+ data: {},
1094
+ filter: {
1095
+ id: upsertModi.id,
1096
+ },
1097
+ };
1098
+ }
1099
+ else {
1100
+ // 直接把这个改成删除
1101
+ (0, assert_1.default)(action2 !== 'remove');
1102
+ return {
1103
+ id: await (0, uuid_1.generateNewIdAsync)(),
1104
+ action: 'update',
1105
+ data: {
1106
+ action,
1107
+ data,
1108
+ },
1109
+ filter: {
1110
+ id: upsertModi.id,
1111
+ },
1112
+ };
1113
+ }
1114
+ }
1115
+ else {
1116
+ // 是update,直接把原来的data覆盖掉
1117
+ if (action !== action2 && process.env.NODE_ENV === 'development') {
1118
+ // 这种情况感觉是不会发生的
1119
+ console.warn('发生了同一行数据的modi的action不一致,请注意查看');
1120
+ }
1121
+ return {
1122
+ id: 'dummy',
1123
+ action: 'update',
1124
+ data: {
1125
+ data: Object.assign({}, data2, data),
1126
+ },
1127
+ filter: {
1128
+ id: id2,
1129
+ }
1130
+ };
1131
+ }
1132
+ }
1133
+ // 说明没有已有的modi,必须要创建新的,此时应当在option中有相应的parentEntity/Id
1134
+ const { modiParentEntity, modiParentId } = option;
1135
+ (0, assert_1.default)(modiParentEntity && modiParentId);
1136
+ return {
1137
+ id: 'dummy',
1138
+ action: 'create',
1139
+ data: {
1140
+ id: operId,
1141
+ targetEntity: entity,
1142
+ entity: modiParentEntity,
1143
+ entityId: modiParentId,
1144
+ action,
1145
+ data,
1146
+ iState: 'active',
1147
+ filter: ids.length > 0 ? {
1148
+ id: {
1149
+ $in: ids,
1150
+ },
1151
+ } : {
1152
+ id: ids[0],
1153
+ },
1154
+ modiEntity$modi: {
1155
+ id: 'dummy',
1156
+ action: 'create',
1157
+ data: await Promise.all(ids.map(async (id) => ({
1158
+ id: await (0, uuid_1.generateNewIdAsync)(),
1159
+ entity: entity,
1160
+ entityId: id,
1161
+ }))),
1162
+ }
1163
+ },
1164
+ };
1165
+ }
1054
1166
  /**
1055
1167
  * 和具体的update过程无关的例程放在这里,包括对later动作的处理、对oper的记录以及对record的收集等
1056
1168
  * @param entity
@@ -1282,100 +1394,60 @@ class CascadeStore extends RowStore_1.RowStore {
1282
1394
  if (data) {
1283
1395
  this.preProcessDataUpdated(action, data, true);
1284
1396
  }
1285
- if (option.modiParentEntity && !['modi', 'modiEntity'].includes(entity)) {
1286
- // 延时更新,变成对modi的插入
1287
- // 变成对modi的插入
1288
- // 优化,这里如果是对同一个targetEntity反复update,则变成对最后一条create/update的modi进行update,以避免发布文章这样的需求时产生过多的modi
1289
- let modiUpsert;
1290
- if (action === 'update') {
1291
- // 如果action本身是update,且没有实际update属性,这里可以忽略
1292
- const updateAttrCount = Object.keys(data).length;
1293
- if (updateAttrCount === 0) {
1294
- return {};
1295
- }
1296
- // 尝试和当前targetEntity的最后一条create/update进行合并,优化modi的条数
1297
- const upsertModis = await this.selectAbjointRowAsync('modi', {
1298
- data: {
1299
- id: 1,
1300
- data: 1,
1301
- action: 1,
1302
- },
1303
- filter: {
1304
- targetEntity: entity,
1305
- entity: option.modiParentEntity,
1306
- entityId: option.modiParentId,
1307
- iState: 'active',
1308
- filter: ids.length > 0 ? {
1309
- id: {
1310
- $in: ids,
1311
- },
1312
- } : filter,
1313
- },
1314
- sorter: [
1315
- {
1316
- $attr: {
1317
- $$createAt$$: 1,
1318
- },
1319
- $direction: 'desc',
1320
- }
1321
- ],
1322
- indexFrom: 0,
1323
- count: 1,
1324
- }, context, option);
1325
- if (upsertModis.length > 0) {
1326
- const { data: originData, id: originId, action } = upsertModis[0];
1327
- if (['create', 'update'].includes(action)) {
1328
- modiUpsert = {
1329
- id: 'dummy',
1330
- action: 'update',
1331
- data: {
1332
- data: Object.assign({}, originData, data),
1333
- },
1334
- filter: {
1335
- id: originId,
1336
- }
1337
- };
1338
- }
1339
- }
1340
- }
1341
- if (!modiUpsert) {
1342
- modiUpsert = {
1343
- id: 'dummy',
1344
- action: 'create',
1345
- data: {
1346
- id: operId,
1347
- targetEntity: entity,
1348
- entity: option.modiParentEntity,
1349
- entityId: option.modiParentId,
1350
- action,
1351
- data,
1352
- iState: 'active',
1353
- filter,
1354
- },
1355
- };
1356
- if (ids.length > 0) {
1357
- modiUpsert.data.modiEntity$modi = {
1358
- id: 'dummy',
1359
- action: 'create',
1360
- data: await Promise.all(ids.map(async (id) => ({
1361
- id: await (0, uuid_1.generateNewIdAsync)(),
1362
- entity: entity,
1363
- entityId: id,
1364
- }))),
1365
- };
1366
- }
1367
- }
1397
+ const createModi = async () => {
1398
+ const modiOperation = await this.tryMergeModi(entity, operation, context, ids, option);
1368
1399
  const closeRootMode = context.openRootMode();
1369
- await this.cascadeUpdateAsync('modi', modiUpsert, context, option);
1400
+ await this.cascadeUpdateAsync('modi', modiOperation, context, option);
1370
1401
  closeRootMode();
1371
1402
  return {
1372
1403
  modi: {
1373
1404
  ['create']: 1,
1374
1405
  },
1375
1406
  };
1407
+ };
1408
+ if (option.modiParentEntity && !['modi', 'modiEntity'].includes(entity)) {
1409
+ // 延时更新,变成对modi的操作
1410
+ if (action === 'update' && Object.keys(data).length === 0) {
1411
+ return {};
1412
+ }
1413
+ return createModi();
1376
1414
  }
1377
1415
  else {
1378
- const createOper = async () => {
1416
+ const saveRecordAndCreateOper = async () => {
1417
+ if (action === 'remove') {
1418
+ if (!option.dontCollect) {
1419
+ context.saveOpRecord(entity, {
1420
+ id: operId,
1421
+ action,
1422
+ data: data,
1423
+ filter: {
1424
+ id: {
1425
+ $in: ids,
1426
+ }
1427
+ },
1428
+ });
1429
+ }
1430
+ }
1431
+ else {
1432
+ const updateAttrCount = Object.keys(data).length;
1433
+ if (updateAttrCount > 0) {
1434
+ if (!option.dontCollect) {
1435
+ context.saveOpRecord(entity, {
1436
+ id: operId,
1437
+ action,
1438
+ data: data,
1439
+ filter: {
1440
+ id: {
1441
+ $in: ids,
1442
+ }
1443
+ },
1444
+ });
1445
+ }
1446
+ }
1447
+ else {
1448
+ return {};
1449
+ }
1450
+ }
1379
1451
  if (!option.dontCreateOper && !['oper', 'operEntity', 'modiEntity', 'modi', 'log'].includes(entity) && ids.length > 0) {
1380
1452
  // 按照框架要求生成Oper和OperEntity这两个内置的对象
1381
1453
  (0, assert_1.default)(operId);
@@ -1412,48 +1484,21 @@ class CascadeStore extends RowStore_1.RowStore {
1412
1484
  });
1413
1485
  closeRootMode();
1414
1486
  }
1487
+ return {
1488
+ [entity]: {
1489
+ [action]: ids.length,
1490
+ }
1491
+ };
1415
1492
  };
1416
- if (action === 'remove') {
1417
- if (!option.dontCollect) {
1418
- context.saveOpRecord(entity, {
1419
- id: operId,
1420
- action,
1421
- data: data,
1422
- filter: {
1423
- id: {
1424
- $in: ids,
1425
- }
1426
- },
1427
- });
1428
- }
1493
+ const count = await this.updateAbjointRowAsync(entity, operation, context, option);
1494
+ if (count === ids.length) {
1495
+ return await saveRecordAndCreateOper();
1429
1496
  }
1430
1497
  else {
1431
- const updateAttrCount = Object.keys(data).length;
1432
- if (updateAttrCount > 0) {
1433
- if (!option.dontCollect) {
1434
- context.saveOpRecord(entity, {
1435
- id: operId,
1436
- action,
1437
- data: data,
1438
- filter: {
1439
- id: {
1440
- $in: ids,
1441
- }
1442
- },
1443
- });
1444
- }
1445
- }
1446
- else {
1447
- return {};
1448
- }
1498
+ // 如果没有更新到行,说明这些数据还在modi当中
1499
+ (0, assert_1.default)(count === 0, 'update成功的行数只能为id所在行数或者0');
1500
+ return await createModi();
1449
1501
  }
1450
- await this.updateAbjointRowAsync(entity, operation, context, option);
1451
- await createOper();
1452
- return {
1453
- [entity]: {
1454
- [action]: ids.length,
1455
- }
1456
- };
1457
1502
  }
1458
1503
  }
1459
1504
  }
@@ -352,12 +352,47 @@ class RelationAuth {
352
352
  const dealWithData = (rows) => {
353
353
  // 这里如果entity指向不同的实体,一般出现这样的查询,则其权限应当不由这条deduce路径处理
354
354
  // 同上,如果找到的行数大于1行,说明deduce路径上的对象不确定,也暂不处理 by Xc 20230725
355
- if (rows.length > 1 || rows.length === 0) {
355
+ if (rows.length > 1) {
356
356
  if (process.env.NODE_ENV === 'development') {
357
357
  console.warn(`进行deduce推导时找到了${rows.length}行${entity}数据`);
358
358
  }
359
359
  return entityFilters;
360
360
  }
361
+ else if (rows.length === 0) {
362
+ // 说明没有找到行,这时候有一种可能是modi。这时候只能假设是指定id更新了,其它情况很难处理。by Xc
363
+ if (filter.id) {
364
+ // 用modi对应的entity/entityId来判定
365
+ const modies = context.select('modi', {
366
+ data: {
367
+ id: 1,
368
+ data: 1,
369
+ entity: 1,
370
+ entityId: 1,
371
+ },
372
+ filter: {
373
+ filter,
374
+ }
375
+ }, {});
376
+ const getModiEntity = (modies) => {
377
+ if (modies[0]) {
378
+ const { entity, entityId } = modies[0];
379
+ entityFilters.push({
380
+ entity: entity,
381
+ filter: {
382
+ id: entityId,
383
+ },
384
+ actions: ['update'],
385
+ });
386
+ }
387
+ return entityFilters;
388
+ };
389
+ if (modies instanceof Promise) {
390
+ return modies.then((modies2) => getModiEntity(modies2));
391
+ }
392
+ return getModiEntity(modies);
393
+ }
394
+ return entityFilters;
395
+ }
361
396
  const { entity: deducedEntity, entityId: deducedEntityId } = rows[0];
362
397
  if (!deducedEntity || !deducedEntityId) {
363
398
  // 这种情况会出现在前台缓存里
@@ -801,6 +836,7 @@ class RelationAuth {
801
836
  */
802
837
  findActionAuthsOnNode(node, context) {
803
838
  const { entity, filter, action, userRelations } = node;
839
+ (0, assert_1.default)(filter);
804
840
  const deducedEntityFilters2 = this.getDeducedEntityFilters(entity, filter, [action], context);
805
841
  /**
806
842
  * 搜索判定是否允许自建对象,自建的条件是 path = '',destEntity === entity
@@ -25,7 +25,6 @@ type FilterPart<A extends string, F extends Object | undefined> = {
25
25
  export type SelectOption = {
26
26
  dontCollect?: boolean;
27
27
  blockTrigger?: true;
28
- obscure?: boolean;
29
28
  forUpdate?: true | 'skip locked' | 'nowait';
30
29
  includedDeleted?: true;
31
30
  ignoreAttrMiss?: true;
@@ -150,7 +150,7 @@ export declare function isStringExpression<A>(expression: any): expression is St
150
150
  export declare function isAggrExpression<A>(expression: any): expression is AggrExpression<A>;
151
151
  export declare function isExpression<A>(expression: any): expression is Expression<A>;
152
152
  export declare function opMultipleParams(op: string): boolean;
153
- export declare function execOp(op: string, params: any, obscure?: boolean): ExpressionConstant;
153
+ export declare function execOp(op: string, params: any): ExpressionConstant;
154
154
  /**
155
155
  * 检查一个表达式,并分析其涉及到的属性
156
156
  * @param expression
@@ -136,10 +136,7 @@ function opMultipleParams(op) {
136
136
  '$round', '$floor', '$ceil', '$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op);
137
137
  }
138
138
  exports.opMultipleParams = opMultipleParams;
139
- function execOp(op, params, obscure) {
140
- if (obscure && (params === undefined || params.includes(undefined))) {
141
- return true;
142
- }
139
+ function execOp(op, params) {
143
140
  switch (op) {
144
141
  case '$gt': {
145
142
  return params[0] > params[1];
@@ -246,28 +246,29 @@ class SimpleConnector {
246
246
  return {};
247
247
  }
248
248
  async fetchWithTimeout(url, options, timeout = 5000) {
249
- if (typeof AbortController === 'undefined') {
250
- return global.fetch(url, options);
251
- }
252
- const controller = new AbortController();
253
- const signal = controller.signal;
254
- // 设置超时
255
- const timeoutId = setTimeout(() => {
256
- controller.abort();
257
- }, timeout);
258
- // 发起 fetch 请求并传递 signal
259
- return global.fetch(url, Object.assign({}, options, { signal }))
260
- .then(response => {
261
- clearTimeout(timeoutId); // 如果请求成功,清除超时
262
- return response;
263
- })
264
- .catch(error => {
265
- clearTimeout(timeoutId); // 如果请求失败,清除超时
266
- if (error.name === 'AbortError') {
267
- throw new types_1.OakRequestTimeoutException();
268
- }
269
- throw error; // 其他错误
270
- });
249
+ return global.fetch(url, options);
250
+ // if (typeof AbortController === 'undefined' || timeout === 0) {
251
+ // return global.fetch(url, options);
252
+ // }
253
+ // const controller = new AbortController();
254
+ // const signal = controller.signal;
255
+ // // 设置超时
256
+ // const timeoutId = setTimeout(() => {
257
+ // controller.abort();
258
+ // }, timeout);
259
+ // // 发起 fetch 请求并传递 signal
260
+ // return global.fetch(url, Object.assign({}, options, { signal }))
261
+ // .then(response => {
262
+ // clearTimeout(timeoutId); // 如果请求成功,清除超时
263
+ // return response;
264
+ // })
265
+ // .catch(error => {
266
+ // clearTimeout(timeoutId); // 如果请求失败,清除超时
267
+ // if (error.name === 'AbortError') {
268
+ // throw new OakRequestTimeoutException();
269
+ // }
270
+ // throw error; // 其他错误
271
+ // });
271
272
  }
272
273
  }
273
274
  exports.default = SimpleConnector;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oak-domain",
3
- "version": "5.1.13",
3
+ "version": "5.1.14",
4
4
  "author": {
5
5
  "name": "XuChang"
6
6
  },