@chevre/domain 22.11.0-alpha.31 → 22.11.0-alpha.33

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.
@@ -0,0 +1,109 @@
1
+ // tslint:disable:no-console
2
+ import * as moment from 'moment';
3
+ import * as mongoose from 'mongoose';
4
+
5
+ import { chevre } from '../../../lib/index';
6
+
7
+ // const project = { id: String(process.env.PROJECT_ID) };
8
+ const MAX_LENGTH = 50;
9
+ const CHECK_DAYS = 60;
10
+
11
+ async function main() {
12
+ await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
13
+
14
+ const orderRepo = await chevre.repository.Order.createInstance(mongoose.connection);
15
+
16
+ const cursor = orderRepo.getCursor(
17
+ {
18
+ typeOf: { $eq: chevre.factory.order.OrderType.Order },
19
+ orderDate: {
20
+ $gte: moment()
21
+ .add(-CHECK_DAYS, 'days')
22
+ .toDate()
23
+ }
24
+ // _id: { $eq: '67de46777ec0510590b68922' }
25
+ },
26
+ {
27
+ customer: 1,
28
+ project: 1,
29
+ orderDate: 1
30
+ }
31
+ );
32
+ console.log('docs found');
33
+
34
+ let i = 0;
35
+ let exceededCount = 0;
36
+ await cursor.eachAsync(async (doc) => {
37
+ i += 1;
38
+ const order: Pick<
39
+ chevre.factory.order.IOrder,
40
+ 'customer' | 'project' | 'orderDate'
41
+ > = doc.toObject();
42
+
43
+ const attributesNames: (keyof chevre.factory.order.ICustomer)[] = [
44
+ 'address',
45
+ 'age',
46
+ 'email',
47
+ 'givenName',
48
+ 'familyName',
49
+ 'gender',
50
+ 'name',
51
+ 'url',
52
+ 'telephone'
53
+ ];
54
+
55
+ const maxLengthNotExceeded = attributesNames.every((attributesName) => {
56
+ const attributesValue = order.customer[attributesName];
57
+ if (attributesValue === undefined) {
58
+ return true;
59
+ }
60
+ if (typeof attributesValue !== 'string') {
61
+ throw new Error(`${attributesName}: ${attributesValue} must be string. ${order.project.id}`);
62
+ }
63
+
64
+ return attributesValue.length <= MAX_LENGTH;
65
+ });
66
+
67
+ if (maxLengthNotExceeded) {
68
+ // no op
69
+ process.stdout.write('-');
70
+ } else {
71
+ exceededCount += 1;
72
+ console.log('\n');
73
+ console.log('maxLengthExceeded.', order.project.id, order.customer, order.orderDate, i);
74
+ }
75
+ });
76
+
77
+ console.log('\n');
78
+ console.log(i, 'docs checked');
79
+ console.log(exceededCount, 'docs exceeded');
80
+
81
+ // let result: any;
82
+ // const attributesNames = [
83
+ // // 'customer.address',
84
+ // // 'customer.age',
85
+ // 'customer.email',
86
+ // 'customer.givenName',
87
+ // 'customer.familyName'
88
+ // // 'customer.gender',
89
+ // // 'customer.name',
90
+ // // 'customer.url',
91
+ // ];
92
+ // for (const attributesName of attributesNames) {
93
+ // console.log('how is', attributesName, '?');
94
+ // result = await orderRepo.checkCustomerAttributesLength({
95
+ // attributesName,
96
+ // length: MAX_LENGTH
97
+ // });
98
+ // // tslint:disable-next-line:no-null-keyword
99
+ // console.dir(result, { depth: null });
100
+ // console.log('how is', attributesName, '?', result.length, 'results found');
101
+ // }
102
+ }
103
+
104
+ main()
105
+ .then(() => {
106
+ console.log('\n');
107
+ console.log('success!');
108
+ })
109
+ .catch(console.error);
@@ -17,7 +17,7 @@ async function main() {
17
17
  });
18
18
  await client.connect();
19
19
 
20
- const itemAvailabilityRepo = await chevre.repository.StockHolder.createInstance(client, mongoose.connection);
20
+ const itemAvailabilityRepo = await chevre.repository.StockHolder.createInstance({ connection: mongoose.connection });
21
21
 
22
22
  const result = await itemAvailabilityRepo.searchHolders({
23
23
  project,
@@ -93,10 +93,10 @@ async function main() {
93
93
  const eventRepo = await chevre.repository.Event.createInstance(mongoose.connection);
94
94
  const projectRepo = await chevre.repository.Project.createInstance(mongoose.connection);
95
95
  // const settingRepo = await chevre.repository.Setting.createInstance(mongoose.connection);
96
- const stockHolderRepo = await chevre.repository.StockHolder.createInstance(
97
- client,
98
- mongoose.connection
99
- );
96
+ const stockHolderRepo = await chevre.repository.StockHolder.createInstance({
97
+ redisClient: client,
98
+ connection: mongoose.connection
99
+ });
100
100
 
101
101
  let checkingProjects: string[] = [];
102
102
  // 全プロジェクト
@@ -2,9 +2,10 @@
2
2
  import * as moment from 'moment';
3
3
  import * as mongoose from 'mongoose';
4
4
 
5
- import { chevre } from '../../../lib/index';
5
+ import { chevre } from '../../../../lib/index';
6
6
 
7
- const TASK_STORAGE_PERIOD_IN_MINUTES = 43200; // 30*24*60
7
+ // const TASK_STORAGE_PERIOD_IN_MINUTES = 43200; // 30*24*60
8
+ const TASK_STORAGE_PERIOD_IN_MINUTES = 28800; // 20*24*60
8
9
 
9
10
  async function main() {
10
11
  const now = new Date();
@@ -12,7 +13,7 @@ async function main() {
12
13
 
13
14
  const taskRepo = await chevre.repository.Task.createInstance(mongoose.connection);
14
15
 
15
- let taskInMinutes = 57600; // 40*24*60
16
+ let taskInMinutes = 44640; // 31*24*60
16
17
  // let taskInMinutes = 172800; // 120*24*60
17
18
  // tslint:disable-next-line:no-magic-numbers
18
19
  while (taskInMinutes > TASK_STORAGE_PERIOD_IN_MINUTES) {
@@ -0,0 +1,23 @@
1
+ // tslint:disable:no-console
2
+ import * as mongoose from 'mongoose';
3
+
4
+ import { chevre } from '../../../../lib/index';
5
+
6
+ async function main() {
7
+ await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
8
+
9
+ const taskRepo = await chevre.repository.Task.createInstance(mongoose.connection);
10
+ const result = await taskRepo.taskModel.deleteMany({
11
+ $or: [
12
+ { name: { $exists: false } },
13
+ { status: { $exists: false } }
14
+ ]
15
+ })
16
+ .exec();
17
+
18
+ console.log('success!', result);
19
+ }
20
+
21
+ main()
22
+ .then()
23
+ .catch(console.error);
@@ -587,6 +587,7 @@ class PendingReservationRepo {
587
587
  throw new factory.errors.AlreadyInUse(factory.reservationType.EventReservation, ['ticketedSeat'], 'Already hold');
588
588
  }
589
589
  }
590
+ throw error;
590
591
  }
591
592
  });
592
593
  }
@@ -9,7 +9,10 @@ export declare class StockHolderRepo implements AbstractStockHolderRepo {
9
9
  static KEY_PREFIX_NEW: string;
10
10
  private readonly redisClient;
11
11
  private readonly pendingReservationRepo;
12
- constructor(redisClient: RedisClientType, connection: Connection);
12
+ constructor(params: {
13
+ redisClient?: RedisClientType;
14
+ connection: Connection;
15
+ });
13
16
  private static offer2field;
14
17
  private static createKey;
15
18
  /**
@@ -54,10 +57,6 @@ export declare class StockHolderRepo implements AbstractStockHolderRepo {
54
57
  eventId: string;
55
58
  startDate: Date;
56
59
  }): Promise<boolean>;
57
- checkIfConflicted(params: {
58
- eventId: string;
59
- startDate: Date;
60
- }): Promise<void>;
61
60
  /**
62
61
  * 万が一に備えて、保留予約をredis->mongo移行
63
62
  */
@@ -13,18 +13,16 @@ exports.StockHolderRepo = void 0;
13
13
  const createDebug = require("debug");
14
14
  const moment = require("moment");
15
15
  const factory = require("../factory");
16
- // import { createSchema, IModel, ISetting, modelName } from './mongoose/schemas/setting';
17
16
  const pendingReservation_1 = require("./pendingReservation");
18
17
  const debug = createDebug('chevre-domain:repo:stockHolder');
19
18
  const SEARCH_OFFERS_MAX_LENGTH = 100;
20
- const USE_STOCK_HOLDER_CHECK_CONFLICT = process.env.USE_STOCK_HOLDER_CHECK_CONFLICT === '1';
21
19
  /**
22
20
  * イベントストックホルダーリポジトリ
23
21
  */
24
22
  class StockHolderRepo {
25
- constructor(redisClient, connection) {
23
+ constructor(params) {
24
+ const { redisClient, connection } = params;
26
25
  this.redisClient = redisClient;
27
- // this.settingModel = connection.model(modelName, createSchema());
28
26
  this.pendingReservationRepo = new pendingReservation_1.PendingReservationRepo(connection);
29
27
  }
30
28
  static offer2field(params, hasTicketedSeat) {
@@ -61,15 +59,15 @@ class StockHolderRepo {
61
59
  hasTicketedSeat: lockKey.hasTicketedSeat
62
60
  });
63
61
  if (useMongoose) {
64
- // throw new factory.errors.NotImplemented('new stock holder repository not implemented');
65
62
  return this.pendingReservationRepo.lockIfNotLimitExceeded(lockKey, maximum);
66
63
  }
67
64
  else {
65
+ if (this.redisClient === undefined) {
66
+ throw new factory.errors.Internal('redisClient required');
67
+ }
68
68
  const key = StockHolderRepo.createKey({ eventId: lockKey.eventId, startDate: lockKey.startDate });
69
69
  yield this.redisClient.watch(key);
70
70
  const hashCount = yield this.redisClient.hLen(key);
71
- // Process result
72
- // Heavy and time consuming operation here
73
71
  debug('checking hash count...hashCount:', hashCount);
74
72
  if (hashCount + lockKey.offers.length > maximum) {
75
73
  throw new factory.errors.Argument('Event', 'maximumAttendeeCapacity exceeded');
@@ -96,10 +94,12 @@ class StockHolderRepo {
96
94
  const key = StockHolderRepo.createKey({ eventId: lockKey.eventId, startDate: lockKey.startDate });
97
95
  // await this.checkIfConflicted({ key, eventId: lockKey.eventId, useMongoose });
98
96
  if (useMongoose) {
99
- // throw new factory.errors.NotImplemented('new stock holder repository not implemented');
100
97
  return this.pendingReservationRepo.lock(lockKey);
101
98
  }
102
99
  else {
100
+ if (this.redisClient === undefined) {
101
+ throw new factory.errors.Internal('redisClient required');
102
+ }
103
103
  const value = lockKey.holder;
104
104
  const multi = this.redisClient.multi();
105
105
  const fields = lockKey.offers.map((offer) => StockHolderRepo.offer2field(offer, lockKey.hasTicketedSeat));
@@ -160,10 +160,12 @@ class StockHolderRepo {
160
160
  const key = StockHolderRepo.createKey({ eventId: params.eventId, startDate: params.startDate });
161
161
  // await this.checkIfConflicted({ key, eventId: params.eventId, useMongoose });
162
162
  if (useMongoose) {
163
- // throw new factory.errors.NotImplemented('new stock holder repository not implemented');
164
163
  return this.pendingReservationRepo.unlock(params);
165
164
  }
166
165
  else {
166
+ if (this.redisClient === undefined) {
167
+ throw new factory.errors.Internal('redisClient required');
168
+ }
167
169
  const field = StockHolderRepo.offer2field(params.offer, params.hasTicketedSeat);
168
170
  yield this.redisClient.multi()
169
171
  .hDel(key, field)
@@ -182,10 +184,12 @@ class StockHolderRepo {
182
184
  startDate: params.event.startDate,
183
185
  hasTicketedSeat: params.event.hasTicketedSeat
184
186
  })) {
185
- // throw new factory.errors.NotImplemented('new stock holder repository not implemented');
186
187
  return this.pendingReservationRepo.countUnavailableOffers(params);
187
188
  }
188
189
  else {
190
+ if (this.redisClient === undefined) {
191
+ throw new factory.errors.Internal('redisClient required');
192
+ }
189
193
  const key = StockHolderRepo.createKey({ eventId: params.event.id, startDate: params.event.startDate });
190
194
  const reply = yield this.redisClient.hLen(key);
191
195
  let fieldCount = 0;
@@ -207,10 +211,12 @@ class StockHolderRepo {
207
211
  startDate: params.startDate,
208
212
  hasTicketedSeat: params.hasTicketedSeat
209
213
  })) {
210
- // throw new factory.errors.NotImplemented('new stock holder repository not implemented');
211
214
  return this.pendingReservationRepo.getHolder(params);
212
215
  }
213
216
  else {
217
+ if (this.redisClient === undefined) {
218
+ throw new factory.errors.Internal('redisClient required');
219
+ }
214
220
  const key = StockHolderRepo.createKey({ eventId: params.eventId, startDate: params.startDate });
215
221
  const field = StockHolderRepo.offer2field(params.offer, params.hasTicketedSeat);
216
222
  return this.redisClient.hGet(key, field);
@@ -229,10 +235,12 @@ class StockHolderRepo {
229
235
  startDate: params.startDate,
230
236
  hasTicketedSeat: params.hasTicketedSeat
231
237
  })) {
232
- // throw new factory.errors.NotImplemented('new stock holder repository not implemented');
233
238
  return this.pendingReservationRepo.searchHolders(params);
234
239
  }
235
240
  else {
241
+ if (this.redisClient === undefined) {
242
+ throw new factory.errors.Internal('redisClient required');
243
+ }
236
244
  const key = StockHolderRepo.createKey({ eventId: params.eventId, startDate: params.startDate });
237
245
  const fields = params.offers.map((o) => {
238
246
  return StockHolderRepo.offer2field(o, params.hasTicketedSeat);
@@ -249,6 +257,9 @@ class StockHolderRepo {
249
257
  }
250
258
  redisKeyExists(params) {
251
259
  return __awaiter(this, void 0, void 0, function* () {
260
+ if (this.redisClient === undefined) {
261
+ throw new factory.errors.Internal('redisClient required');
262
+ }
252
263
  const key = StockHolderRepo.createKey(params);
253
264
  const existingRedisKeyCount = yield this.redisClient.exists(key);
254
265
  if (typeof existingRedisKeyCount !== 'number') {
@@ -257,20 +268,24 @@ class StockHolderRepo {
257
268
  return existingRedisKeyCount > 0;
258
269
  });
259
270
  }
260
- checkIfConflicted(params) {
261
- return __awaiter(this, void 0, void 0, function* () {
262
- const redisKeyExists = yield this.redisKeyExists(params);
263
- const mongoDocExists = yield this.pendingReservationRepo.docExists(params);
264
- if (redisKeyExists && mongoDocExists) {
265
- throw new factory.errors.Internal(`repository conflicted. eventId:${params.eventId}`);
266
- }
267
- });
268
- }
271
+ // public async checkIfConflicted(params: {
272
+ // eventId: string;
273
+ // startDate: Date;
274
+ // }): Promise<void> {
275
+ // const redisKeyExists = await this.redisKeyExists(params);
276
+ // const mongoDocExists = await this.pendingReservationRepo.docExists(params);
277
+ // if (redisKeyExists && mongoDocExists) {
278
+ // throw new factory.errors.Internal(`repository conflicted. eventId:${params.eventId}`);
279
+ // }
280
+ // }
269
281
  /**
270
282
  * 万が一に備えて、保留予約をredis->mongo移行
271
283
  */
272
284
  migrate2mongoJustInCase(params) {
273
285
  return __awaiter(this, void 0, void 0, function* () {
286
+ if (this.redisClient === undefined) {
287
+ throw new factory.errors.Internal('redisClient required');
288
+ }
274
289
  const redisKey = StockHolderRepo.createKey({ eventId: params.eventId, startDate: params.startDate });
275
290
  return {
276
291
  expireTime: yield this.redisClient.expireTime(redisKey),
@@ -281,26 +296,27 @@ class StockHolderRepo {
281
296
  /**
282
297
  * 新リポジトリを使用するかどうか
283
298
  */
299
+ // tslint:disable-next-line:prefer-function-over-method
284
300
  useMongoose(params) {
285
301
  return __awaiter(this, void 0, void 0, function* () {
286
302
  if (!(params.startDate instanceof Date)) {
287
303
  throw new factory.errors.Argument('startDate', 'must be Date');
288
304
  }
289
- let useMongoose = false;
290
- // always use mongo(2025-05-21~)
291
- const redisKeyExists = yield this.redisKeyExists(params);
292
- if (redisKeyExists) {
293
- useMongoose = false;
294
- }
295
- else {
296
- // redis keyが存在しなければmongo利用
297
- useMongoose = true;
298
- }
299
- // check confliction for test
300
- if (USE_STOCK_HOLDER_CHECK_CONFLICT) {
301
- yield this.checkIfConflicted(params);
302
- }
303
- return useMongoose;
305
+ // always use mongo(2025-08-17~)
306
+ return true;
307
+ // let useMongoose = false;
308
+ // const redisKeyExists = await this.redisKeyExists(params);
309
+ // if (redisKeyExists) {
310
+ // useMongoose = false;
311
+ // } else {
312
+ // // redis keyが存在しなければmongo利用
313
+ // useMongoose = true;
314
+ // }
315
+ // // check confliction for test
316
+ // if (USE_STOCK_HOLDER_CHECK_CONFLICT) {
317
+ // await this.checkIfConflicted(params);
318
+ // }
319
+ // return useMongoose;
304
320
  });
305
321
  }
306
322
  }
@@ -119,12 +119,15 @@ export declare class TaskRepo {
119
119
  * 実行日時を一定期間過ぎたReadyタスクについて、Runningスタータスに変更した上で、Runningイベントを発生させる
120
120
  */
121
121
  emitRunningIfExists(params: {
122
- name?: {
123
- $eq?: factory.taskName;
124
- $in?: factory.taskName[];
125
- };
126
- executor: {
127
- name: string;
122
+ /**
123
+ * 必ずタスク名指定で実行する
124
+ */
125
+ name: {
126
+ $eq: factory.taskName;
127
+ $in?: never;
128
+ } | {
129
+ $eq?: never;
130
+ $in: factory.taskName[];
128
131
  };
129
132
  runsAt: {
130
133
  $lt: Date;
@@ -133,6 +136,10 @@ export declare class TaskRepo {
133
136
  numberOfTried?: factory.sortType;
134
137
  runsAt?: factory.sortType;
135
138
  };
139
+ executor: {
140
+ name: string;
141
+ };
142
+ nameFilterBeforeRunsAt: boolean;
136
143
  }, next?: INextFunction): Promise<Pick<factory.task.ITask<factory.taskName>, 'id' | 'name'> | null>;
137
144
  /**
138
145
  * Readyのままで期限切れのタスクをExpiredに変更する
@@ -460,7 +460,7 @@ class TaskRepo {
460
460
  emitRunningIfExists(params, next // support next function(2025-08-02~)
461
461
  ) {
462
462
  return __awaiter(this, void 0, void 0, function* () {
463
- var _a, _b;
463
+ var _a;
464
464
  if (!(params.runsAt.$lt instanceof Date)) {
465
465
  throw new factory.errors.Argument('runsAt.$lt', 'must be Date');
466
466
  }
@@ -471,12 +471,20 @@ class TaskRepo {
471
471
  };
472
472
  const nameEq = (_a = params.name) === null || _a === void 0 ? void 0 : _a.$eq;
473
473
  // const nameNin = params.name?.$nin;
474
- const nameIn = (_b = params.name) === null || _b === void 0 ? void 0 : _b.$in;
475
- const doc = yield this.taskModel.findOneAndUpdate(Object.assign({ status: { $eq: factory.taskStatus.Ready }, runsAt: { $lt: params.runsAt.$lt } }, (typeof nameEq === 'string' || Array.isArray(nameIn))
476
- ? {
477
- name: Object.assign(Object.assign({}, (typeof nameEq === 'string') ? { $eq: nameEq } : undefined), (Array.isArray(nameIn)) ? { $in: nameIn } : undefined)
478
- }
479
- : undefined), {
474
+ // const nameIn = params.name?.$in;
475
+ const { nameFilterBeforeRunsAt } = params;
476
+ const filter = Object.assign(Object.assign(Object.assign({ status: { $eq: factory.taskStatus.Ready } }, (nameFilterBeforeRunsAt) ? { name: params.name } : undefined), { runsAt: { $lt: params.runsAt.$lt } }), (!nameFilterBeforeRunsAt) ? { name: params.name } : undefined
477
+ // ...(typeof nameEq === 'string' || Array.isArray(nameIn))
478
+ // ? {
479
+ // name: {
480
+ // ...(typeof nameEq === 'string') ? { $eq: nameEq } : undefined,
481
+ // // ...(Array.isArray(nameNin)) ? { $nin: nameNin } : undefined
482
+ // ...(Array.isArray(nameIn)) ? { $in: nameIn } : undefined
483
+ // }
484
+ // }
485
+ // : undefined
486
+ );
487
+ const doc = yield this.taskModel.findOneAndUpdate(filter, {
480
488
  $set: {
481
489
  status: factory.taskStatus.Running, // 実行中に変更
482
490
  lastTriedAt: new Date(),
@@ -32,7 +32,7 @@ function call(data) {
32
32
  yield (0, aggregateOffers_1.aggregateOffers)(data)({
33
33
  aggregateReservation: new aggregateReservation_1.AggregateReservationRepo(connection),
34
34
  event: new event_1.EventRepo(connection),
35
- stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection),
35
+ stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection }),
36
36
  offer: new unitPriceInCatalog_1.OfferRepo(connection),
37
37
  offerCatalog: new offerCatalog_1.OfferCatalogRepo(connection),
38
38
  offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
@@ -32,7 +32,7 @@ function call(data) {
32
32
  }
33
33
  yield AggregationService.event.aggregateScreeningEvent(data)({
34
34
  event: new event_1.EventRepo(connection),
35
- stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection),
35
+ stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection }),
36
36
  offer: new unitPriceInCatalog_1.OfferRepo(connection),
37
37
  offerCatalog: new offerCatalog_1.OfferCatalogRepo(connection),
38
38
  offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
@@ -43,7 +43,7 @@ function call(params) {
43
43
  yield (0, cancelReservation_1.cancelPendingReservation)({ purpose: data.purpose })({
44
44
  action: new action_1.ActionRepo(connection),
45
45
  assetTransaction: new assetTransaction_1.AssetTransactionRepo(connection),
46
- stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection),
46
+ stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection }),
47
47
  offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
48
48
  reservation: new reservation_1.ReservationRepo(connection),
49
49
  setting: new setting_1.SettingRepo(connection),
@@ -34,7 +34,7 @@ function call(data) {
34
34
  task: new task_1.TaskRepo(connection),
35
35
  assetTransaction: new assetTransaction_1.AssetTransactionRepo(connection),
36
36
  offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
37
- stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection)
37
+ stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection })
38
38
  }
39
39
  // settings
40
40
  );
@@ -59,7 +59,7 @@ function call(data) {
59
59
  project: { id: data.project.id }
60
60
  })({
61
61
  event: new event_1.EventRepo(connection),
62
- stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection)
62
+ stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection })
63
63
  });
64
64
  break;
65
65
  default:
@@ -64,7 +64,7 @@ function call(params) {
64
64
  yield (0, voidTransaction_1.voidTransaction)(Object.assign(Object.assign({}, params.data), { project: { id: params.project.id }, sameAs: { id: params.id } }))({
65
65
  action: new action_1.ActionRepo(connection),
66
66
  assetTransaction: new assetTransaction_1.AssetTransactionRepo(connection),
67
- stockHolder: new stockHolder_1.StockHolderRepo(redisClient, connection),
67
+ stockHolder: new stockHolder_1.StockHolderRepo({ redisClient, connection }),
68
68
  offerRateLimit: new offer_1.OfferRateLimitRepo(redisClient),
69
69
  orderInTransaction: new orderInTransaction_1.OrderInTransactionRepo(connection),
70
70
  reservation: new reservation_1.ReservationRepo(connection),
@@ -1,11 +1,11 @@
1
1
  import type { EventRepo } from '../../repo/event';
2
2
  import type { StockHolderRepo } from '../../repo/stockHolder';
3
- export declare function validateEvent(params: {
3
+ export declare function validateEvent(__: {
4
4
  id: string;
5
5
  project: {
6
6
  id: string;
7
7
  };
8
- }): (repos: {
8
+ }): (__2: {
9
9
  event: EventRepo;
10
10
  stockHolder: StockHolderRepo;
11
11
  }) => Promise<void>;
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ // import * as createDebug from 'debug';
2
3
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
4
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
5
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -10,15 +11,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
11
  };
11
12
  Object.defineProperty(exports, "__esModule", { value: true });
12
13
  exports.validateEvent = validateEvent;
13
- const createDebug = require("debug");
14
- const debug = createDebug('chevre-domain:service:validation');
15
- function validateEvent(params) {
16
- return (repos) => __awaiter(this, void 0, void 0, function* () {
17
- const event = yield repos.event.projectEventFieldsById({ id: params.id }, ['startDate']);
18
- debug('validateEvent: conflicted?', params.project.id, event.id, event.startDate);
19
- yield repos.stockHolder.checkIfConflicted({
20
- eventId: event.id,
21
- startDate: event.startDate
22
- });
14
+ // import * as factory from '../../factory';
15
+ // const debug = createDebug('chevre-domain:service:validation');
16
+ function validateEvent(__) {
17
+ return (__2) => __awaiter(this, void 0, void 0, function* () {
18
+ // const event: Pick<factory.event.screeningEvent.IEvent, 'id' | 'startDate'> =
19
+ // await repos.event.projectEventFieldsById<factory.eventType.ScreeningEvent>(
20
+ // { id: params.id },
21
+ // ['startDate']
22
+ // );
23
+ // discontinue redis(2025-08-17~)
24
+ // debug('validateEvent: conflicted?', params.project.id, event.id, event.startDate);
25
+ // await repos.stockHolder.checkIfConflicted({
26
+ // eventId: event.id,
27
+ // startDate: event.startDate
28
+ // });
23
29
  });
24
30
  }
package/package.json CHANGED
@@ -115,5 +115,5 @@
115
115
  "postversion": "git push origin --tags",
116
116
  "prepublishOnly": "npm run clean && npm run build && npm test && npm run doc"
117
117
  },
118
- "version": "22.11.0-alpha.31"
118
+ "version": "22.11.0-alpha.33"
119
119
  }
@@ -1,76 +0,0 @@
1
- // tslint:disable:no-console
2
- import * as moment from 'moment';
3
- import * as mongoose from 'mongoose';
4
- import * as redis from 'redis';
5
-
6
- import { chevre } from '../../../../lib/index';
7
-
8
- // const project = { id: String(process.env.PROJECT_ID) };
9
- const excludedProject = { id: String(process.env.EXCLUDED_PROJECT_ID) };
10
-
11
- const client = redis.createClient<redis.RedisDefaultModules, Record<string, never>, Record<string, never>>({
12
- socket: {
13
- port: Number(<string>process.env.REDIS_PORT),
14
- host: <string>process.env.REDIS_HOST
15
- },
16
- password: <string>process.env.REDIS_KEY
17
- })
18
- .on('error', (err) => {
19
- // eslint-disable-next-line no-console
20
- console.error('createDefaultRedisClient: client onError:', err);
21
- // reject(err);
22
- });
23
- client.connect();
24
- mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
25
-
26
- // tslint:disable-next-line:max-func-body-length
27
- async function main() {
28
- const eventRepo = await chevre.repository.Event.createInstance(mongoose.connection);
29
- const stockHolderRepo = await chevre.repository.StockHolder.createInstance(
30
- client,
31
- mongoose.connection
32
- );
33
-
34
- const cursor = eventRepo.getCursor(
35
- {
36
- 'project.id': { $ne: excludedProject.id },
37
- startDate: {
38
- $gte: moment()
39
- .add(-1, 'days')
40
- .toDate()
41
- },
42
- typeOf: { $eq: chevre.factory.eventType.ScreeningEvent }
43
- // _id: { $eq: 'blyk9q24f' }
44
- },
45
- {
46
- _id: 1,
47
- // offers: 1,
48
- startDate: 1,
49
- project: 1,
50
- typeOf: 1
51
- }
52
- );
53
- console.log('events found');
54
-
55
- let i = 0;
56
- await cursor.eachAsync(async (doc) => {
57
- i += 1;
58
- const event: Pick<
59
- chevre.factory.event.screeningEvent.IEvent,
60
- 'id' | 'startDate' | 'project' | 'typeOf'
61
- > = doc.toObject();
62
-
63
- console.log(
64
- 'conflicted?', event.project.id, event.typeOf, event.id, event.startDate, i);
65
- await stockHolderRepo.checkIfConflicted({
66
- eventId: event.id,
67
- startDate: event.startDate
68
- });
69
- });
70
-
71
- console.log(i, 'events checked');
72
- }
73
-
74
- main()
75
- .then()
76
- .catch(console.error);
@@ -1,96 +0,0 @@
1
- // tslint:disable:no-console
2
- import * as moment from 'moment-timezone';
3
- import * as mongoose from 'mongoose';
4
- import * as redis from 'redis';
5
- import { ILockKey } from '../../../../lib/chevre/repo/stockHolderAbstract';
6
- import { chevre } from '../../../../lib/index';
7
-
8
- const client = redis.createClient<redis.RedisDefaultModules, Record<string, never>, Record<string, never>>({
9
- socket: {
10
- port: Number(<string>process.env.REDIS_PORT),
11
- host: <string>process.env.REDIS_HOST
12
- },
13
- password: <string>process.env.REDIS_KEY
14
- })
15
- .on('error', (err) => {
16
- // eslint-disable-next-line no-console
17
- console.error('createDefaultRedisClient: client onError:', err);
18
- // reject(err);
19
- });
20
- client.connect();
21
- mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
22
-
23
- const EVENT_ID = 'cm8dwc74c';
24
-
25
- async function main() {
26
- // 万が一に備えて、保留予約をredis->mongo移行するスクリプト
27
- const assetTransactionRepo = await chevre.repository.AssetTransaction.createInstance(mongoose.connection);
28
- const eventRepo = await chevre.repository.Event.createInstance(mongoose.connection);
29
- // const pendingReservationRepo = await chevre.repository.PendingReservation.createInstance(mongoose.connection);
30
- const stockHolderRepo = await chevre.repository.StockHolder.createInstance(client, mongoose.connection);
31
-
32
- const event = await eventRepo.projectEventFieldsById(
33
- { id: EVENT_ID },
34
- ['startDate', 'organizer', 'project', 'offers']
35
- );
36
- const hasTicketedSeat = event.offers.itemOffered.serviceOutput?.reservedTicket?.ticketedSeat?.typeOf === chevre.factory.placeType.Seat;
37
- const { expireTime, hash } = await stockHolderRepo.migrate2mongoJustInCase({
38
- eventId: EVENT_ID,
39
- startDate: event.startDate
40
- // project: { id: event.project.id },
41
- // provider: { id: event.organizer.id }
42
- });
43
- console.log(expireTime, hash);
44
-
45
- const lockKeys: ILockKey[] = [];
46
- const reservationNumbers: string[] = [...new Set(Object.values(hash))];
47
- const expires: Date = moment.unix(expireTime)
48
- .toDate();
49
- console.log('reservationNumbers:', reservationNumbers);
50
- console.log('expires:', expires);
51
-
52
- // 予約番号ごとにlockKeyを作成する
53
- for (const reservationNumber of reservationNumbers) {
54
- const reserveTransaction = (await assetTransactionRepo.search<chevre.factory.assetTransactionType.Reserve>(
55
- {
56
- limit: 1,
57
- page: 1,
58
- transactionNumber: { $eq: reservationNumber },
59
- typeOf: chevre.factory.assetTransactionType.Reserve,
60
- status: { $in: [chevre.factory.transactionStatusType.Confirmed] }
61
- },
62
- ['object', 'startDate']
63
- )).shift();
64
- if (reserveTransaction === undefined) {
65
- throw new Error(`reserveTransaction not found ${reservationNumber}`);
66
- }
67
-
68
- const fields: string[] = Object.keys(hash)
69
- .filter((field) => hash[field] === reservationNumber);
70
- const lockKey: ILockKey = {
71
- project: { id: event.project.id },
72
- provider: { id: event.organizer.id },
73
- eventId: EVENT_ID,
74
- startDate: event.startDate,
75
- hasTicketedSeat,
76
- offers: fields.map((field) => {
77
- const splitedField = field.split(':');
78
-
79
- return {
80
- seatSection: splitedField[0],
81
- seatNumber: splitedField[1]
82
- };
83
- }),
84
- expires,
85
- holder: reservationNumber,
86
- bookingTime: reserveTransaction.startDate
87
- };
88
- console.log('lockKey:', lockKey);
89
- lockKeys.push(lockKey);
90
- // await pendingReservationRepo.lock(lockKey);
91
- }
92
- }
93
-
94
- main()
95
- .then(console.log)
96
- .catch(console.error);
@@ -1,256 +0,0 @@
1
- // tslint:disable:no-console
2
- import * as moment from 'moment-timezone';
3
- import * as mongoose from 'mongoose';
4
- import * as redis from 'redis';
5
- import { chevre } from '../../../../lib/index';
6
-
7
- const today = moment()
8
- .tz('Asia/Tokyo')
9
- .format('YYYYMMDD');
10
- const project = { id: String(process.env.PROJECT_ID) };
11
- const providerId = 'sampleProviderId';
12
- const eventId = `sampleEventId${today}:03`;
13
- const eventStartDate = new Date('2025-05-01T00:00:00Z');
14
- const expires = moment(eventStartDate)
15
- .add(1, 'week')
16
- .toDate();
17
- const seatSection = 'SampleSectionNameXXXXXXXXXXXXXXXXXXX';
18
- // tslint:disable-next-line:no-magic-numbers prefer-array-literal
19
- const allSeatNumbers = [...Array(10000)].map((__, seatKey) => `SampleSeatNumber-${seatKey}`);
20
- const OPERATION_INTERVAL = 2000;
21
- // const MAXIMUM_CAPACITY = 10002;
22
-
23
- mongoose.Model.on('index', (...args) => {
24
- console.error('******** index event emitted. ********\n', args);
25
- });
26
-
27
- async function sleep(waitTime: number): Promise<void> {
28
- return new Promise<void>((resolve) => {
29
- setTimeout(
30
- () => {
31
- resolve();
32
- },
33
- waitTime
34
- );
35
- });
36
- }
37
-
38
- const client = redis.createClient<redis.RedisDefaultModules, Record<string, never>, Record<string, never>>({
39
- socket: {
40
- port: Number(<string>process.env.REDIS_PORT),
41
- host: <string>process.env.REDIS_HOST
42
- },
43
- password: <string>process.env.REDIS_KEY
44
- })
45
- .on('error', (err) => {
46
- // eslint-disable-next-line no-console
47
- console.error('createDefaultRedisClient: client onError:', err);
48
- // reject(err);
49
- });
50
- client.connect();
51
- mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
52
-
53
- const formatter = new Intl.NumberFormat('ja-JP');
54
- // => "1,000"
55
-
56
- // tslint:disable-next-line:max-func-body-length
57
- async function lockSeatsForcibly(params: {
58
- maximumCapacity?: number;
59
- }) {
60
- const { maximumCapacity } = params;
61
- let startTime: [number, number] = process.hrtime();
62
- let diff: [number, number] = process.hrtime(startTime);
63
-
64
- const stockHolderRepo = await chevre.repository.StockHolder.createInstance(
65
- client,
66
- mongoose.connection
67
- );
68
-
69
- startTime = process.hrtime();
70
- console.log('counting unavailableOffers...');
71
- let countUnavailableOffersResult = await stockHolderRepo.countUnavailableOffers({
72
- project: { id: project.id },
73
- event: {
74
- id: eventId,
75
- startDate: eventStartDate,
76
- hasTicketedSeat: true
77
- }
78
- });
79
- console.log('countUnavailableOffersResult:', countUnavailableOffersResult);
80
- console.log('diff:', [diff[0], formatter.format(diff[1])]);
81
-
82
- await sleep(OPERATION_INTERVAL);
83
- startTime = process.hrtime();
84
- console.log('counting searching holders...');
85
- const searchHoldersResult = await stockHolderRepo.searchHolders({
86
- project: { id: project.id },
87
- eventId,
88
- startDate: eventStartDate,
89
- hasTicketedSeat: true,
90
- offers: [
91
- // tslint:disable-next-line:no-magic-numbers
92
- ...allSeatNumbers.slice(0, 100)
93
- .map((seatNumber) => ({ seatSection, seatNumber }))
94
- ]
95
- });
96
- diff = process.hrtime(startTime);
97
- console.log('searchHoldersResult.length:', searchHoldersResult.length);
98
- console.log('diff:', [diff[0], formatter.format(diff[1])]);
99
-
100
- // select 2 seats
101
- // tslint:disable-next-line:insecure-random
102
- const seatNumber1 = allSeatNumbers[Math.floor(allSeatNumbers.length * Math.random())];
103
- const seatNumber2 = allSeatNumbers.filter((seatNumber) => seatNumber !== seatNumber1)[
104
- // tslint:disable-next-line:insecure-random
105
- Math.floor((allSeatNumbers.length - 1) * Math.random())
106
- ];
107
-
108
- const seatNumbers = [seatNumber1, seatNumber2];
109
- console.log('seats selected.', seatNumbers);
110
-
111
- let locked = false;
112
- while (!locked) {
113
- await sleep(OPERATION_INTERVAL);
114
- startTime = process.hrtime();
115
- const currentHolders: string[] = [];
116
- for (const seatNumber of seatNumbers) {
117
- const currentHolder = await stockHolderRepo.getHolder({
118
- project: { id: project.id },
119
- eventId,
120
- startDate: eventStartDate,
121
- hasTicketedSeat: true,
122
- offer: { seatSection, seatNumber }
123
- });
124
- if (typeof currentHolder === 'string') {
125
- currentHolders.push(currentHolder);
126
- }
127
- }
128
- diff = process.hrtime(startTime);
129
- console.log('currentHolders:', currentHolders);
130
- console.log('diff:', [diff[0], formatter.format(diff[1])]);
131
-
132
- try {
133
- await sleep(OPERATION_INTERVAL);
134
- const newHolder = Date.now()
135
- .toString();
136
- const bookingTime = new Date();
137
- startTime = process.hrtime();
138
- console.log('locking...', newHolder, seatSection, seatNumbers);
139
- if (typeof maximumCapacity === 'number') {
140
- try {
141
- await stockHolderRepo.lockIfNotLimitExceeded(
142
- {
143
- project: { id: project.id },
144
- provider: { id: providerId },
145
- eventId,
146
- startDate: eventStartDate,
147
- hasTicketedSeat: true,
148
- offers: seatNumbers.map((seatNumber) => ({ seatSection, seatNumber })),
149
- expires,
150
- holder: newHolder,
151
- bookingTime
152
- },
153
- maximumCapacity
154
- );
155
- } catch (error) {
156
- if (error.message === 'maximumAttendeeCapacity exceeded') {
157
- // ok
158
- } else {
159
- throw error;
160
- }
161
- }
162
- } else {
163
- await stockHolderRepo.lock({
164
- project: { id: project.id },
165
- provider: { id: providerId },
166
- eventId,
167
- startDate: eventStartDate,
168
- hasTicketedSeat: true,
169
- offers: seatNumbers.map((seatNumber) => ({ seatSection, seatNumber })),
170
- expires,
171
- holder: newHolder,
172
- bookingTime
173
- });
174
- }
175
- diff = process.hrtime(startTime);
176
- console.log('locked.', newHolder);
177
- console.log('diff:', [diff[0], formatter.format(diff[1])]);
178
- locked = true;
179
- } catch (error) {
180
- if (error instanceof chevre.factory.errors.AlreadyInUse) {
181
- console.log('lockResult:', error.name, error.message);
182
- } else {
183
- console.error(error);
184
- }
185
- }
186
-
187
- await sleep(OPERATION_INTERVAL);
188
- for (const currentHolder of currentHolders) {
189
- for (const seatNumber of seatNumbers) {
190
- startTime = process.hrtime();
191
- console.log('unlocking...', currentHolder, seatSection, seatNumber);
192
- const unlockResult = await stockHolderRepo.unlock({
193
- project: { id: project.id },
194
- eventId,
195
- startDate: eventStartDate,
196
- hasTicketedSeat: true,
197
- offer: { seatSection, seatNumber },
198
- holder: currentHolder
199
- });
200
- diff = process.hrtime(startTime);
201
- console.log('unlockResult:', unlockResult);
202
- console.log('diff:', [diff[0], formatter.format(diff[1])]);
203
- }
204
- }
205
- }
206
-
207
- await sleep(OPERATION_INTERVAL);
208
- countUnavailableOffersResult = await stockHolderRepo.countUnavailableOffers({
209
- project: { id: project.id },
210
- event: {
211
- id: eventId,
212
- startDate: eventStartDate,
213
- hasTicketedSeat: true
214
- }
215
- });
216
- console.log('countUnavailableOffersResult:', countUnavailableOffersResult);
217
-
218
- }
219
-
220
- async function main() {
221
- // tslint:disable-next-line:no-magic-numbers
222
- const numLock = (typeof process.argv[2] === 'string') ? Number(process.argv[2]) : 1;
223
- // tslint:disable-next-line:no-magic-numbers
224
- const maximumCapacity = (typeof process.argv[3] === 'string') ? Number(process.argv[3]) : undefined;
225
-
226
- const LOCK_INTERVAL = 300;
227
- let i = 0;
228
- let lockedCount = 0;
229
- let timeout: NodeJS.Timeout;
230
- const processStartDate = new Date();
231
- function onSeatsLocked() {
232
- lockedCount += 1;
233
- console.log(lockedCount, 'lockSeatsForcibly executed!');
234
- console.log('processed.', processStartDate, '~', new Date());
235
- }
236
-
237
- timeout = setInterval(
238
- () => {
239
- if (i >= numLock) {
240
- clearInterval(timeout);
241
-
242
- return;
243
- }
244
-
245
- i += 1;
246
- lockSeatsForcibly({ maximumCapacity })
247
- .then(onSeatsLocked)
248
- .catch(console.error);
249
- },
250
- LOCK_INTERVAL
251
- );
252
- }
253
-
254
- main()
255
- .then()
256
- .catch(console.error);