@chevre/domain 22.10.0-alpha.9 → 22.11.0-alpha.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.
Files changed (107) hide show
  1. package/example/src/chevre/adminAuth/adminIdentity.ts +38 -0
  2. package/example/src/chevre/adminIdentities.ts +8 -8
  3. package/example/src/chevre/assetTransaction/processReserve.ts +4 -1
  4. package/example/src/chevre/concurrentLock/lockOfferRateLimit.ts +64 -0
  5. package/example/src/chevre/concurrentLock/lockTransactionProcess.ts +44 -0
  6. package/example/src/chevre/createTaskIfNotExistByAlternateName.ts +1 -1
  7. package/example/src/chevre/findOneAvailableHours.ts +11 -11
  8. package/example/src/chevre/identity/getCommonClients.ts +126 -0
  9. package/example/src/chevre/identity/migrateClients2oauth.ts +200 -0
  10. package/example/src/chevre/issuer/adminMemberProgramTiers.ts +55 -0
  11. package/example/src/chevre/maintenance/checkTransactionStatuses.ts +105 -0
  12. package/example/src/chevre/migrateIdentities.ts +24 -37
  13. package/example/src/chevre/reIndex.ts +1 -1
  14. package/example/src/chevre/roles/addPermissionIfNotExists.ts +27 -0
  15. package/example/src/chevre/roles/addRoleMembers.ts +75 -0
  16. package/example/src/chevre/saveWebSite.ts +14 -17
  17. package/example/src/chevre/stockHolder/checkRedisKeyCount.ts +43 -22
  18. package/example/src/chevre/transactionNumber/publishConfimationNumber.ts +37 -0
  19. package/example/src/chevre/transactionNumber/publishOrderNumber.ts +40 -0
  20. package/example/src/chevre/transactionNumber/setUseMongo4confirmationNumberFrom.ts +45 -0
  21. package/example/src/chevre/transactionNumber/setUseMongo4orderNumberFrom.ts +41 -0
  22. package/example/src/chevre/transactionNumber/setUseMongo4transactionNumberFrom.ts +41 -0
  23. package/example/src/redisMulti.ts +63 -0
  24. package/example/src/signPayload.ts +1 -1
  25. package/lib/chevre/adminAuth.d.ts +2 -0
  26. package/lib/chevre/adminAuth.js +6 -0
  27. package/lib/chevre/eventEmitter/task.d.ts +36 -6
  28. package/lib/chevre/eventEmitter/task.js +5 -4
  29. package/lib/chevre/eventEmitter.d.ts +2 -2
  30. package/lib/chevre/eventEmitter.js +2 -2
  31. package/lib/chevre/index.d.ts +2 -0
  32. package/lib/chevre/index.js +10 -0
  33. package/lib/chevre/repo/concurrentLock.d.ts +14 -0
  34. package/lib/chevre/repo/concurrentLock.js +48 -0
  35. package/lib/chevre/repo/concurrentLockAbstract.d.ts +42 -0
  36. package/lib/chevre/repo/concurrentLockAbstract.js +9 -0
  37. package/lib/chevre/repo/confirmationNumber.d.ts +17 -4
  38. package/lib/chevre/repo/confirmationNumber.js +89 -32
  39. package/lib/chevre/repo/identity.d.ts +42 -5
  40. package/lib/chevre/repo/identity.js +35 -4
  41. package/lib/chevre/repo/issuer.d.ts +10 -2
  42. package/lib/chevre/repo/member.js +2 -2
  43. package/lib/chevre/repo/memberProgram.d.ts +43 -2
  44. package/lib/chevre/repo/memberProgram.js +79 -8
  45. package/lib/chevre/repo/mongoose/schemas/issuer.d.ts +3 -1
  46. package/lib/chevre/repo/mongoose/schemas/issuer.js +10 -0
  47. package/lib/chevre/repo/mongoose/schemas/offer/event.js +30 -2
  48. package/lib/chevre/repo/mongoose/schemas/role.d.ts +2 -3
  49. package/lib/chevre/repo/mongoose/schemas/role.js +11 -1
  50. package/lib/chevre/repo/mongoose/schemas/setting.d.ts +3 -0
  51. package/lib/chevre/repo/mongoose/schemas/setting.js +4 -1
  52. package/lib/chevre/repo/mongoose/schemas/transactionNumber.d.ts +39 -0
  53. package/lib/chevre/repo/mongoose/schemas/transactionNumber.js +101 -0
  54. package/lib/chevre/repo/orderNumber.d.ts +15 -4
  55. package/lib/chevre/repo/orderNumber.js +71 -24
  56. package/lib/chevre/repo/passport.d.ts +1 -1
  57. package/lib/chevre/repo/passport.js +31 -13
  58. package/lib/chevre/repo/rateLimit/offer.d.ts +7 -2
  59. package/lib/chevre/repo/rateLimit/offer.js +41 -40
  60. package/lib/chevre/repo/role.d.ts +18 -4
  61. package/lib/chevre/repo/role.js +53 -4
  62. package/lib/chevre/repo/serviceOutputIdentifier.d.ts +8 -4
  63. package/lib/chevre/repo/serviceOutputIdentifier.js +54 -22
  64. package/lib/chevre/repo/stockHolder.d.ts +0 -2
  65. package/lib/chevre/repo/stockHolder.js +24 -31
  66. package/lib/chevre/repo/task.d.ts +10 -25
  67. package/lib/chevre/repo/task.js +65 -36
  68. package/lib/chevre/repo/transactionNumber.d.ts +15 -4
  69. package/lib/chevre/repo/transactionNumber.js +67 -22
  70. package/lib/chevre/repo/transactionNumberCounter.d.ts +28 -0
  71. package/lib/chevre/repo/transactionNumberCounter.js +128 -0
  72. package/lib/chevre/repo/transactionProcess.d.ts +7 -4
  73. package/lib/chevre/repo/transactionProcess.js +34 -13
  74. package/lib/chevre/service/aggregation/event/aggregateOffers.js +1 -0
  75. package/lib/chevre/service/assetTransaction/reserve/start.js +9 -1
  76. package/lib/chevre/service/assetTransaction/reserve/validateStartRequest.js +1 -1
  77. package/lib/chevre/service/code.js +1 -1
  78. package/lib/chevre/service/offer/event/checkAvailability.d.ts +1 -1
  79. package/lib/chevre/service/offer/event/checkAvailability.js +1 -0
  80. package/lib/chevre/service/offer/product.js +0 -40
  81. package/lib/chevre/service/payment/any.d.ts +0 -2
  82. package/lib/chevre/service/payment/any.js +1 -0
  83. package/lib/chevre/service/reserve/cancelReservation.d.ts +3 -0
  84. package/lib/chevre/service/reserve/cancelReservation.js +5 -1
  85. package/lib/chevre/service/task/acceptCOAOffer.js +2 -2
  86. package/lib/chevre/service/task/authorizePayment.js +4 -4
  87. package/lib/chevre/service/task/givePointAward.js +1 -1
  88. package/lib/chevre/service/task/moneyTransfer.js +1 -1
  89. package/lib/chevre/service/task/publishPaymentUrl.js +2 -2
  90. package/lib/chevre/service/task/refund.js +1 -1
  91. package/lib/chevre/service/task/returnMoneyTransfer.js +1 -1
  92. package/lib/chevre/service/task/returnPayTransaction.js +1 -1
  93. package/lib/chevre/service/task/returnPointAward.js +1 -1
  94. package/lib/chevre/service/task/returnReserveTransaction.js +1 -1
  95. package/lib/chevre/service/task.d.ts +8 -17
  96. package/lib/chevre/service/task.js +14 -5
  97. package/lib/chevre/service/transaction/placeOrder/start/validateStartRequest.js +2 -2
  98. package/lib/chevre/service/transaction/returnOrder/preStart/factory.d.ts +20 -0
  99. package/lib/chevre/service/transaction/returnOrder/preStart/factory.js +2 -0
  100. package/lib/chevre/service/transaction/returnOrder/preStart/findApplicableReturnPolicy.d.ts +23 -0
  101. package/lib/chevre/service/transaction/returnOrder/preStart/findApplicableReturnPolicy.js +323 -0
  102. package/lib/chevre/service/transaction/returnOrder/preStart/getReturnPolicyByProject.d.ts +13 -0
  103. package/lib/chevre/service/transaction/returnOrder/preStart/getReturnPolicyByProject.js +132 -0
  104. package/lib/chevre/service/transaction/returnOrder/preStart.js +2 -391
  105. package/package.json +3 -3
  106. package/example/src/chevre/migrateMembers2identities.ts +0 -109
  107. package/example/src/chevre/publishConfimationNumber.ts +0 -27
@@ -13,7 +13,7 @@ exports.StockHolderRepo = void 0;
13
13
  const createDebug = require("debug");
14
14
  const moment = require("moment");
15
15
  const factory = require("../factory");
16
- const setting_1 = require("./mongoose/schemas/setting");
16
+ // import { createSchema, IModel, ISetting, modelName } from './mongoose/schemas/setting';
17
17
  const pendingReservation_1 = require("./pendingReservation");
18
18
  const debug = createDebug('chevre-domain:repo:stockHolder');
19
19
  const SEARCH_OFFERS_MAX_LENGTH = 100;
@@ -24,7 +24,7 @@ const USE_STOCK_HOLDER_CHECK_CONFLICT = process.env.USE_STOCK_HOLDER_CHECK_CONFL
24
24
  class StockHolderRepo {
25
25
  constructor(redisClient, connection) {
26
26
  this.redisClient = redisClient;
27
- this.settingModel = connection.model(setting_1.modelName, (0, setting_1.createSchema)());
27
+ // this.settingModel = connection.model(modelName, createSchema());
28
28
  this.pendingReservationRepo = new pendingReservation_1.PendingReservationRepo(connection);
29
29
  }
30
30
  static offer2field(params, hasTicketedSeat) {
@@ -251,8 +251,10 @@ class StockHolderRepo {
251
251
  return __awaiter(this, void 0, void 0, function* () {
252
252
  const key = StockHolderRepo.createKey(params);
253
253
  const existingRedisKeyCount = yield this.redisClient.exists(key);
254
- // console.log('existingRedisKeyCount:', existingRedisKeyCount);
255
- return typeof existingRedisKeyCount === 'number' && existingRedisKeyCount > 0;
254
+ if (typeof existingRedisKeyCount !== 'number') {
255
+ throw new factory.errors.Internal(`unexpected existingKeyCount: ${typeof existingRedisKeyCount}`);
256
+ }
257
+ return existingRedisKeyCount > 0;
256
258
  });
257
259
  }
258
260
  checkIfConflicted(params) {
@@ -286,16 +288,24 @@ class StockHolderRepo {
286
288
  }
287
289
  let useMongoose = false;
288
290
  // useMongoAsStockHolder設定有の場合のみmongo利用(2025-04-18~)
289
- const useMongoAsStockHolderBySettings = yield this.useMongoAsStockHolderBySettings({ project: { id: params.project.id } });
290
- if (useMongoAsStockHolderBySettings) {
291
- const redisKeyExists = yield this.redisKeyExists(params);
292
- if (redisKeyExists) {
293
- useMongoose = false;
294
- }
295
- else {
296
- // redis keyが存在しなければmongo利用
297
- useMongoose = true;
298
- }
291
+ // const useMongoAsStockHolderBySettings = await this.useMongoAsStockHolderBySettings({ project: { id: params.project.id } });
292
+ // if (useMongoAsStockHolderBySettings) {
293
+ // const redisKeyExists = await this.redisKeyExists(params);
294
+ // if (redisKeyExists) {
295
+ // useMongoose = false;
296
+ // } else {
297
+ // // redis keyが存在しなければmongo利用
298
+ // useMongoose = true;
299
+ // }
300
+ // }
301
+ // always use mongo(2025-05-21~)
302
+ const redisKeyExists = yield this.redisKeyExists(params);
303
+ if (redisKeyExists) {
304
+ useMongoose = false;
305
+ }
306
+ else {
307
+ // redis keyが存在しなければmongo利用
308
+ useMongoose = true;
299
309
  }
300
310
  // check confliction for test
301
311
  if (USE_STOCK_HOLDER_CHECK_CONFLICT) {
@@ -304,23 +314,6 @@ class StockHolderRepo {
304
314
  return useMongoose;
305
315
  });
306
316
  }
307
- useMongoAsStockHolderBySettings(params) {
308
- return __awaiter(this, void 0, void 0, function* () {
309
- // useMongoAsStockHolder設定有の場合のみmongo利用(2025-04-18~)
310
- const setting = yield this.settingModel.findOne({ 'project.id': { $eq: '*' } }, {
311
- _id: 0,
312
- useMongoAsStockHolder: 1,
313
- useMongoAsStockHolderProjects: 1
314
- })
315
- .lean()
316
- .exec();
317
- const useMongoGlobally = (setting === null || setting === void 0 ? void 0 : setting.useMongoAsStockHolder) === true;
318
- const useMongoAsStockHolderProjects = setting === null || setting === void 0 ? void 0 : setting.useMongoAsStockHolderProjects;
319
- const useMongoByProject = Array.isArray(useMongoAsStockHolderProjects)
320
- && useMongoAsStockHolderProjects.includes(params.project.id);
321
- return useMongoGlobally || useMongoByProject;
322
- });
323
- }
324
317
  }
325
318
  exports.StockHolderRepo = StockHolderRepo;
326
319
  StockHolderRepo.KEY_PREFIX_NEW = 'stockHolder';
@@ -1,4 +1,5 @@
1
1
  import type { AnyKeys, Connection, FilterQuery, ProjectionType, UpdateWriteOpResult } from 'mongoose';
2
+ import { INextFunction } from '../eventEmitter/task';
2
3
  import * as factory from '../factory';
3
4
  import { IModel } from './mongoose/schemas/task';
4
5
  interface IAggregationByStatus {
@@ -23,7 +24,6 @@ interface IOptionOnCreate {
23
24
  }
24
25
  export type IExecutableTaskKeys = 'data' | 'id' | 'name' | 'status' | 'numberOfTried' | 'project' | 'remainingNumberOfTries' | 'runsAt' | 'expires';
25
26
  export type IExecutableTask<T extends factory.taskName> = Pick<factory.task.ITask<T>, IExecutableTaskKeys>;
26
- type IDelayedTask = Pick<factory.task.ITask<factory.taskName>, 'id' | 'name' | 'status'>;
27
27
  type IKeyOfProjection = keyof factory.task.ITask<factory.taskName>;
28
28
  type ICreatingTask = Pick<factory.task.IAttributes<factory.taskName>, 'data' | 'executionResults' | 'name' | 'numberOfTried' | 'project' | 'remainingNumberOfTries' | 'runsAt' | 'status' | 'identifier' | 'description'>;
29
29
  /**
@@ -36,7 +36,8 @@ export declare class TaskRepo {
36
36
  runImmediately(params: Pick<factory.task.IAttributes<factory.taskName>, 'data' | 'expires' | 'name' | 'project' | 'remainingNumberOfTries' | 'runsAt'> & {
37
37
  alternateName?: never;
38
38
  identifier?: never;
39
- }): Promise<{
39
+ expires: Date;
40
+ }, next: INextFunction): Promise<{
40
41
  id: string;
41
42
  }>;
42
43
  saveMany(taskAttributes: ICreatingTask[], options: IOptionOnCreate): Promise<{
@@ -133,24 +134,6 @@ export declare class TaskRepo {
133
134
  /**
134
135
  * emit OnTaskStatusChanged on delayed tasks
135
136
  */
136
- emitDelayedTasksEvent(params: {
137
- now: Date;
138
- /**
139
- * 指定期間遅延しているタスクを実行する
140
- */
141
- delayInSeconds: number;
142
- limit: number;
143
- name: {
144
- /**
145
- * 指定タスクのみ実行する
146
- */
147
- $in?: factory.taskName[];
148
- /**
149
- * 指定タスク以外のみ実行する
150
- */
151
- $nin?: factory.taskName[];
152
- };
153
- }): Promise<IDelayedTask[]>;
154
137
  /**
155
138
  * make tasks expired
156
139
  */
@@ -180,11 +163,13 @@ export declare class TaskRepo {
180
163
  /**
181
164
  * 実行結果を保管する
182
165
  */
183
- pushExecutionResultById(
184
- /**
185
- * タスクID
186
- */
187
- id: string, status: factory.taskStatus, executionResult: factory.task.IExecutionResult): Promise<void>;
166
+ pushExecutionResultById(params: {
167
+ /**
168
+ * タスクID
169
+ */
170
+ id: string;
171
+ status: factory.taskStatus;
172
+ }, executionResult: factory.task.IExecutionResult, next?: INextFunction): Promise<void>;
188
173
  /**
189
174
  * 特定タスク検索
190
175
  */
@@ -156,7 +156,9 @@ class TaskRepo {
156
156
  }
157
157
  runImmediately(
158
158
  // resolve uniqueness of identifier(2025-03-27~)
159
- params) {
159
+ params,
160
+ // support customr function(2025-05-25~)
161
+ next) {
160
162
  return __awaiter(this, void 0, void 0, function* () {
161
163
  var _a, _b;
162
164
  const { expires } = params;
@@ -173,7 +175,7 @@ class TaskRepo {
173
175
  id,
174
176
  status: factory.taskStatus.Ready,
175
177
  expires // emit expires(2025-03-31~)
176
- });
178
+ }, next);
177
179
  return { id };
178
180
  });
179
181
  }
@@ -623,38 +625,62 @@ class TaskRepo {
623
625
  return doc;
624
626
  });
625
627
  }
628
+ // discontinue(2025-05-26~)
626
629
  /**
627
630
  * emit OnTaskStatusChanged on delayed tasks
628
631
  */
629
- emitDelayedTasksEvent(params) {
630
- return __awaiter(this, void 0, void 0, function* () {
631
- const runsAtLt = moment(params.now)
632
- .add(-params.delayInSeconds, 'seconds')
633
- .toDate();
634
- const projection = {
635
- _id: 0,
636
- id: { $toString: '$_id' },
637
- name: 1,
638
- status: 1
639
- };
640
- const delayedTasks = yield this.taskModel.find(Object.assign(Object.assign({ status: { $eq: factory.taskStatus.Ready }, runsAt: { $lt: runsAtLt } }, (Array.isArray(params.name.$in)) ? { name: { $in: params.name.$in } } : undefined), (Array.isArray(params.name.$nin)) ? { name: { $nin: params.name.$nin } } : undefined), projection)
641
- .limit(params.limit)
642
- .sort(sortOrder4executionOfTasks) // sort(2025-03-03~)
643
- .setOptions({ maxTimeMS: settings_1.MONGO_MAX_TIME_MS })
644
- .lean() // lean(2024-09-26~)
645
- .exec();
646
- if (delayedTasks.length > 0) {
647
- delayedTasks.forEach((delayedTask) => {
648
- task_1.taskEventEmitter.emitTaskStatusChanged({
649
- id: delayedTask.id,
650
- name: delayedTask.name,
651
- status: factory.taskStatus.Ready
652
- });
653
- });
654
- }
655
- return delayedTasks;
656
- });
657
- }
632
+ // public async emitDelayedTasksEvent(params: {
633
+ // now: Date;
634
+ // /**
635
+ // * 指定期間遅延しているタスクを実行する
636
+ // */
637
+ // delayInSeconds: number;
638
+ // limit: number;
639
+ // name: {
640
+ // /**
641
+ // * 指定タスクのみ実行する
642
+ // */
643
+ // $in?: factory.taskName[];
644
+ // /**
645
+ // * 指定タスク以外のみ実行する
646
+ // */
647
+ // $nin?: factory.taskName[];
648
+ // };
649
+ // }) {
650
+ // const runsAtLt = moment(params.now)
651
+ // .add(-params.delayInSeconds, 'seconds')
652
+ // .toDate();
653
+ // const projection: ProjectionType<factory.task.ITask<factory.taskName>> = {
654
+ // _id: 0,
655
+ // id: { $toString: '$_id' },
656
+ // name: 1,
657
+ // status: 1
658
+ // };
659
+ // const delayedTasks = await this.taskModel.find(
660
+ // {
661
+ // status: { $eq: factory.taskStatus.Ready },
662
+ // runsAt: { $lt: runsAtLt },
663
+ // ...(Array.isArray(params.name.$in)) ? { name: { $in: params.name.$in } } : undefined,
664
+ // ...(Array.isArray(params.name.$nin)) ? { name: { $nin: params.name.$nin } } : undefined
665
+ // },
666
+ // projection
667
+ // )
668
+ // .limit(params.limit)
669
+ // .sort(sortOrder4executionOfTasks) // sort(2025-03-03~)
670
+ // .setOptions({ maxTimeMS: MONGO_MAX_TIME_MS })
671
+ // .lean<IDelayedTask[]>() // lean(2024-09-26~)
672
+ // .exec();
673
+ // if (delayedTasks.length > 0) {
674
+ // delayedTasks.forEach((delayedTask) => {
675
+ // taskEventEmitter.emitTaskStatusChanged({
676
+ // id: delayedTask.id,
677
+ // name: delayedTask.name,
678
+ // status: factory.taskStatus.Ready
679
+ // });
680
+ // });
681
+ // }
682
+ // return delayedTasks;
683
+ // }
658
684
  /**
659
685
  * make tasks expired
660
686
  */
@@ -770,17 +796,20 @@ class TaskRepo {
770
796
  /**
771
797
  * 実行結果を保管する
772
798
  */
773
- pushExecutionResultById(
774
- /**
775
- * タスクID
776
- */
777
- id, status, executionResult) {
799
+ pushExecutionResultById(params, executionResult,
800
+ // support customr function(2025-05-25~)
801
+ next) {
778
802
  return __awaiter(this, void 0, void 0, function* () {
803
+ const { id, status } = params;
779
804
  yield this.taskModel.updateOne({ _id: { $eq: id } }, {
780
805
  $set: { status },
781
806
  $push: { executionResults: executionResult }
782
807
  })
783
808
  .exec();
809
+ // emit event(2025-05-26~)
810
+ if (typeof next === 'function') {
811
+ task_1.taskEventEmitter.emitTaskStatusChanged({ id, status, executionResult }, next);
812
+ }
784
813
  });
785
814
  }
786
815
  /**
@@ -1,4 +1,6 @@
1
+ import type { Connection } from 'mongoose';
1
2
  import { RedisClientType } from 'redis';
3
+ import { ISetting } from './mongoose/schemas/setting';
2
4
  interface IPublishResult {
3
5
  transactionNumber: string;
4
6
  }
@@ -6,15 +8,24 @@ interface IPublishResult {
6
8
  * 取引番号リポジトリ
7
9
  */
8
10
  export declare class TransactionNumberRepo {
9
- private static readonly REDIS_KEY_PREFIX;
10
- private readonly redisClient;
11
- constructor(redisClient: RedisClientType);
12
- private static createKey;
11
+ private readonly settingModel;
12
+ private readonly counterRepo;
13
+ constructor(params: {
14
+ redisClient: RedisClientType;
15
+ connection: Connection;
16
+ });
13
17
  /**
14
18
  * タイムスタンプから発行する
15
19
  */
16
20
  publishByTimestamp(params: {
17
21
  startDate: Date;
18
22
  }): Promise<IPublishResult>;
23
+ /**
24
+ * DB移行時のみに使用目的の設定更新
25
+ */
26
+ setUseMongo4transactionNumberFrom(params: {
27
+ useMongo4transactionNumberFrom: Date;
28
+ }): Promise<Pick<ISetting, "useMongo4transactionNumberFrom"> | null>;
29
+ private useMongoBySettings;
19
30
  }
20
31
  export {};
@@ -12,20 +12,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.TransactionNumberRepo = void 0;
13
13
  const cdigit = require("cdigit");
14
14
  const moment = require("moment-timezone");
15
- const util = require("util");
16
15
  // tslint:disable-next-line:no-require-imports no-var-requires
17
16
  const fpe = require('node-fpe');
18
- const factory = require("../factory");
17
+ const setting_1 = require("./mongoose/schemas/setting");
18
+ const transactionNumber_1 = require("./mongoose/schemas/transactionNumber");
19
+ const transactionNumberCounter_1 = require("./transactionNumberCounter");
19
20
  /**
20
21
  * 取引番号リポジトリ
21
22
  */
22
23
  class TransactionNumberRepo {
23
- constructor(redisClient) {
24
- this.redisClient = redisClient;
25
- }
26
- static createKey(params) {
27
- return util.format('%s:%s', TransactionNumberRepo.REDIS_KEY_PREFIX, params.timestamp);
24
+ constructor(params) {
25
+ const { connection } = params;
26
+ this.settingModel = connection.model(setting_1.modelName, (0, setting_1.createSchema)());
27
+ this.counterRepo = new transactionNumberCounter_1.TransactionNumberCounterRepo(params);
28
28
  }
29
+ // private static createKey(params: {
30
+ // startDate: Date;
31
+ // timestamp: string;
32
+ // }): string {
33
+ // return util.format(
34
+ // '%s:%s',
35
+ // TransactionNumberRepo.REDIS_KEY_PREFIX,
36
+ // params.timestamp
37
+ // );
38
+ // }
29
39
  /**
30
40
  * タイムスタンプから発行する
31
41
  */
@@ -34,20 +44,29 @@ class TransactionNumberRepo {
34
44
  const timestamp = moment(params.startDate)
35
45
  .valueOf()
36
46
  .toString();
37
- const now = moment();
38
- const TTL = moment(params.startDate)
39
- .add(1, 'minute') // ミリ秒でカウントしていくので、予約日時後1分で十分
40
- .diff(now, 'seconds');
41
- const key = TransactionNumberRepo.createKey({ startDate: params.startDate, timestamp });
42
- const [incrReply] = yield this.redisClient.multi()
43
- .incr(key)
44
- .expire(key, TTL)
45
- .exec();
46
- // tslint:disable-next-line:no-single-line-block-comment
47
- /* istanbul ignore else: please write tests */
48
- if (typeof incrReply !== 'number') {
49
- // 基本的にありえないフロー
50
- throw new factory.errors.Internal('transaction number not incremented unexpectedly');
47
+ let dataFeedExpires;
48
+ const dataFeedIdentifier = timestamp;
49
+ let incrReply;
50
+ const useMongoBySettings = yield this.useMongoBySettings(params);
51
+ if (useMongoBySettings) {
52
+ dataFeedExpires = moment(params.startDate)
53
+ .add(1, 'minute') // ミリ秒でカウントしていくので、予約日時後1分で十分
54
+ .toDate();
55
+ incrReply = yield this.counterRepo.incrementByMongo({
56
+ identifier: dataFeedIdentifier,
57
+ includedInDataCatalog: { identifier: transactionNumber_1.DataCatalogIdentifier.transactionNumber },
58
+ expires: dataFeedExpires
59
+ });
60
+ }
61
+ else {
62
+ dataFeedExpires = moment(params.startDate)
63
+ .add(1, 'minute') // ミリ秒でカウントしていくので、予約日時後1分で十分
64
+ .toDate();
65
+ incrReply = yield this.counterRepo.incrementByRedis({
66
+ identifier: dataFeedIdentifier,
67
+ includedInDataCatalog: { identifier: transactionNumber_1.DataCatalogIdentifier.transactionNumber },
68
+ expires: dataFeedExpires
69
+ });
51
70
  }
52
71
  let transactionNumber = `${timestamp}${incrReply}`;
53
72
  // checkdigit
@@ -58,6 +77,32 @@ class TransactionNumberRepo {
58
77
  return { transactionNumber };
59
78
  });
60
79
  }
80
+ /**
81
+ * DB移行時のみに使用目的の設定更新
82
+ */
83
+ setUseMongo4transactionNumberFrom(params) {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ const { useMongo4transactionNumberFrom } = params;
86
+ return this.settingModel.findOneAndUpdate({ 'project.id': { $eq: '*' } }, {
87
+ $set: { useMongo4transactionNumberFrom }
88
+ }, { projection: { _id: 0, useMongo4transactionNumberFrom: 1 } })
89
+ .lean()
90
+ .exec();
91
+ });
92
+ }
93
+ useMongoBySettings(params) {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ const setting = yield this.settingModel.findOne({ 'project.id': { $eq: '*' } }, {
96
+ _id: 0,
97
+ useMongo4transactionNumberFrom: 1
98
+ })
99
+ .lean()
100
+ .exec();
101
+ const useMongo4transactionNumberFrom = setting === null || setting === void 0 ? void 0 : setting.useMongo4transactionNumberFrom;
102
+ return useMongo4transactionNumberFrom instanceof Date
103
+ && moment(params.startDate)
104
+ .isSameOrAfter(moment(useMongo4transactionNumberFrom));
105
+ });
106
+ }
61
107
  }
62
108
  exports.TransactionNumberRepo = TransactionNumberRepo;
63
- TransactionNumberRepo.REDIS_KEY_PREFIX = 'transactionNumber';
@@ -0,0 +1,28 @@
1
+ import type { Connection } from 'mongoose';
2
+ import { RedisClientType } from 'redis';
3
+ import { DataCatalogIdentifier } from './mongoose/schemas/transactionNumber';
4
+ /**
5
+ * 取引番号カウンターリポジトリ
6
+ */
7
+ export declare class TransactionNumberCounterRepo {
8
+ private readonly redisClient;
9
+ private readonly transactionNumberModel;
10
+ constructor(params: {
11
+ redisClient: RedisClientType;
12
+ connection: Connection;
13
+ });
14
+ incrementByRedis(params: {
15
+ identifier: string;
16
+ includedInDataCatalog: {
17
+ identifier: DataCatalogIdentifier;
18
+ };
19
+ expires: Date;
20
+ }): Promise<number>;
21
+ incrementByMongo(params: {
22
+ identifier: string;
23
+ includedInDataCatalog: {
24
+ identifier: DataCatalogIdentifier;
25
+ };
26
+ expires: Date;
27
+ }): Promise<number>;
28
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.TransactionNumberCounterRepo = void 0;
13
+ const errorHandler_1 = require("../errorHandler");
14
+ const factory = require("../factory");
15
+ const transactionNumber_1 = require("./mongoose/schemas/transactionNumber");
16
+ const MAX_RETRY_INCREMENT = 1;
17
+ /**
18
+ * 取引番号カウンターリポジトリ
19
+ */
20
+ class TransactionNumberCounterRepo {
21
+ constructor(params) {
22
+ const { redisClient, connection } = params;
23
+ this.redisClient = redisClient;
24
+ this.transactionNumberModel = connection.model(transactionNumber_1.modelName, (0, transactionNumber_1.createSchema)());
25
+ }
26
+ incrementByRedis(params) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ // const now = moment();
29
+ const { expires } = params;
30
+ const key = `${params.includedInDataCatalog.identifier}:${params.identifier}`;
31
+ // const TTL = moment(expires)
32
+ // .diff(now, 'seconds');
33
+ const [incrReply, expireAtReply] = yield this.redisClient.multi()
34
+ .incr(key)
35
+ // .expire(key, TTL)
36
+ .expireAt(key, expires)
37
+ .exec();
38
+ // tslint:disable-next-line:no-single-line-block-comment
39
+ /* istanbul ignore else: please write tests */
40
+ if (typeof incrReply !== 'number') {
41
+ // 基本的にありえないフロー
42
+ throw new factory.errors.Internal('transaction number not incremented unexpectedly');
43
+ }
44
+ // expireAtReplyの検証も追加する(2023-04-19~)
45
+ const expiredSet = expireAtReply === 1 || expireAtReply === true;
46
+ if (!expiredSet) {
47
+ // 基本的にありえないフロー
48
+ throw new factory.errors.Internal('transaction number expiration not set unexpectedly');
49
+ }
50
+ return incrReply;
51
+ });
52
+ }
53
+ incrementByMongo(params) {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ var _a;
56
+ const now = new Date();
57
+ const dataFeedExpires = params.expires;
58
+ const dataFeedIdentifier = params.identifier;
59
+ const dataFeed = {
60
+ typeOf: 'DataFeed',
61
+ includedInDataCatalog: {
62
+ identifier: params.includedInDataCatalog.identifier,
63
+ typeOf: 'DataCatalog'
64
+ },
65
+ dateCreated: now,
66
+ expires: dataFeedExpires,
67
+ identifier: dataFeedIdentifier,
68
+ interactionStatistic: {
69
+ typeOf: 'InteractionCounter',
70
+ userInteractionCount: 0
71
+ },
72
+ project: { id: '*', typeOf: factory.organizationType.Project }
73
+ };
74
+ const { typeOf, includedInDataCatalog, dateCreated, expires, identifier, project, interactionStatistic } = dataFeed;
75
+ let doc;
76
+ let retryCount = 0;
77
+ while (retryCount <= MAX_RETRY_INCREMENT) {
78
+ try {
79
+ doc = yield this.transactionNumberModel.findOneAndUpdate({
80
+ 'project.id': { $eq: dataFeed.project.id },
81
+ 'includedInDataCatalog.identifier': { $eq: dataFeed.includedInDataCatalog.identifier },
82
+ identifier: { $eq: dataFeed.identifier }
83
+ }, {
84
+ $set: {
85
+ dateModified: now
86
+ },
87
+ $setOnInsert: {
88
+ typeOf, includedInDataCatalog, dateCreated, expires, identifier, project,
89
+ 'interactionStatistic.typeOf': interactionStatistic.typeOf
90
+ },
91
+ $inc: {
92
+ 'interactionStatistic.userInteractionCount': 1
93
+ }
94
+ }, {
95
+ upsert: true,
96
+ new: true,
97
+ projection: { _id: 0, interactionStatistic: 1 }
98
+ })
99
+ .lean()
100
+ .exec();
101
+ break;
102
+ }
103
+ catch (error) {
104
+ if (yield (0, errorHandler_1.isMongoError)(error)) {
105
+ if (error.code === errorHandler_1.MongoErrorCode.DuplicateKey) {
106
+ // すでに存在するので、リトライすればincrementに成功するはず
107
+ retryCount += 1;
108
+ continue;
109
+ }
110
+ }
111
+ throw error;
112
+ }
113
+ }
114
+ if (doc === undefined) {
115
+ throw new factory.errors.NotFound('DataFeed');
116
+ }
117
+ const incrReply = (_a = doc.interactionStatistic) === null || _a === void 0 ? void 0 : _a.userInteractionCount;
118
+ // tslint:disable-next-line:no-single-line-block-comment
119
+ /* istanbul ignore if */
120
+ if (typeof incrReply !== 'number') {
121
+ // 基本的にありえないフロー
122
+ throw new factory.errors.Internal('confirmation number not incremented unexpectedly');
123
+ }
124
+ return incrReply;
125
+ });
126
+ }
127
+ }
128
+ exports.TransactionNumberCounterRepo = TransactionNumberCounterRepo;
@@ -6,6 +6,9 @@ interface IProcessKey {
6
6
  * 取引ID
7
7
  */
8
8
  id: string;
9
+ project: {
10
+ id: string;
11
+ };
9
12
  }
10
13
  interface IOptions {
11
14
  lockExpiresInSeconds: number;
@@ -14,11 +17,11 @@ interface IOptions {
14
17
  * 取引プロセスリポジトリ
15
18
  */
16
19
  export declare class TransactionProcessRepo {
20
+ private readonly concurrentLockRepo;
17
21
  private readonly options;
18
- private readonly redisClient;
19
22
  constructor(redisClient: RedisClientType, options: IOptions);
20
- static CREATE_REDIS_KEY(params: IProcessKey): string;
21
- lock(params: IProcessKey): Promise<boolean>;
22
- unlock(params: IProcessKey): Promise<void>;
23
+ static CREATE_REDIS_KEY(params: Pick<IProcessKey, 'id' | 'typeOf'>): string;
24
+ lock(params: IProcessKey): Promise<void>;
25
+ unlock(params: Pick<IProcessKey, 'id' | 'typeOf'>): Promise<void>;
23
26
  }
24
27
  export {};