@chevre/domain 21.2.0-alpha.119 → 21.2.0-alpha.120

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.
@@ -1,5 +1,6 @@
1
1
  import { Connection } from 'mongoose';
2
2
  import { RedisClientType } from 'redis';
3
+ import * as factory from '../factory';
3
4
  export interface IOffer {
4
5
  itemOffered?: {
5
6
  serviceOutput?: {
@@ -25,6 +26,31 @@ export interface IUnlockKey {
25
26
  offer: IOffer;
26
27
  }
27
28
  export type IGetHolderResult = string | null;
29
+ export interface ISubReservation {
30
+ id?: string;
31
+ identifier: string;
32
+ reservedTicket?: {
33
+ ticketedSeat?: Pick<factory.reservation.ISeat<factory.reservationType>, 'seatNumber' | 'seatSection'>;
34
+ };
35
+ }
36
+ export interface IReservationPackage {
37
+ typeOf: factory.reservationType.ReservationPackage;
38
+ reservationNumber: string;
39
+ subReservation: ISubReservation[];
40
+ }
41
+ export interface IAggregateReservation {
42
+ typeOf: 'AggregateReservation';
43
+ reservationCount: number;
44
+ reservationFor: {
45
+ id: string;
46
+ startDate: Date;
47
+ };
48
+ reservations: IReservationPackage[];
49
+ }
50
+ export interface ISearchSubReservationResult {
51
+ reservationNumber: string;
52
+ identifier: string;
53
+ }
28
54
  /**
29
55
  * イベントストックホルダーリポジトリ
30
56
  */
@@ -35,6 +61,7 @@ export declare class StockHolderRepository {
35
61
  private readonly holdReservationModel;
36
62
  constructor(redisClient: RedisClientType, connection: Connection);
37
63
  private static offer2field;
64
+ private static offer2subReservation;
38
65
  private static createKey;
39
66
  /**
40
67
  * 新リポジトリを使用するかどうか
@@ -78,4 +105,5 @@ export declare class StockHolderRepository {
78
105
  offers: IOffer[];
79
106
  }): Promise<IGetHolderResult[]>;
80
107
  private checkIfConflicted;
108
+ private initializeHoldReservation;
81
109
  }
@@ -39,6 +39,25 @@ class StockHolderRepository {
39
39
  }
40
40
  return `${params.seatSection}:${params.seatNumber}`;
41
41
  }
42
+ static offer2subReservation(params) {
43
+ var _a, _b;
44
+ const serviceOutputId = (_b = (_a = params.itemOffered) === null || _a === void 0 ? void 0 : _a.serviceOutput) === null || _b === void 0 ? void 0 : _b.id;
45
+ if (typeof serviceOutputId === 'string') {
46
+ return {
47
+ id: serviceOutputId,
48
+ identifier: serviceOutputId
49
+ };
50
+ }
51
+ return {
52
+ identifier: `${params.seatSection}:${params.seatNumber}`,
53
+ reservedTicket: {
54
+ ticketedSeat: {
55
+ seatSection: params.seatSection,
56
+ seatNumber: params.seatNumber
57
+ }
58
+ }
59
+ };
60
+ }
42
61
  static createKey(params) {
43
62
  if (!(params.startDate instanceof Date)) {
44
63
  throw new factory.errors.Argument('startDate', 'must be Date');
@@ -67,7 +86,34 @@ class StockHolderRepository {
67
86
  lockIfNotLimitExceeded(lockKey, maximum) {
68
87
  return __awaiter(this, void 0, void 0, function* () {
69
88
  if (StockHolderRepository.useMongoose({ eventId: lockKey.eventId, startDate: lockKey.startDate })) {
70
- throw new factory.errors.NotImplemented(`new stock holder repository not implemented for the event '${lockKey.eventId}'`);
89
+ // reservationCount<=nであれば$push+$incする
90
+ yield this.initializeHoldReservation({ eventId: lockKey.eventId, startDate: lockKey.startDate });
91
+ const addedReservationCount = lockKey.offers.length;
92
+ const reservationCountLte = maximum - addedReservationCount;
93
+ const subReservations = lockKey.offers.map((offer) => StockHolderRepository.offer2subReservation(offer));
94
+ const reservationPackage = {
95
+ typeOf: factory.reservationType.ReservationPackage,
96
+ reservationNumber: lockKey.holder,
97
+ subReservation: subReservations
98
+ };
99
+ yield this.holdReservationModel.findOneAndUpdate({
100
+ reservationCount: { $lte: reservationCountLte },
101
+ 'reservationFor.id': { $eq: lockKey.eventId },
102
+ // 座席有無に関わらずsubReservation.identifierはuniqueであるはず
103
+ 'reservations.subReservation.identifier': {
104
+ $nin: subReservations.map((r) => r.identifier)
105
+ }
106
+ }, {
107
+ $inc: { reservationCount: addedReservationCount },
108
+ $push: { reservations: reservationPackage }
109
+ }, { new: true })
110
+ .select({ _id: 1 })
111
+ .exec()
112
+ .then((doc) => {
113
+ if (doc === null) {
114
+ throw new factory.errors.Argument('Event', 'maximumAttendeeCapacity exceeded');
115
+ }
116
+ });
71
117
  }
72
118
  else {
73
119
  const key = StockHolderRepository.createKey({ eventId: lockKey.eventId, startDate: lockKey.startDate });
@@ -89,7 +135,31 @@ class StockHolderRepository {
89
135
  lock(lockKey) {
90
136
  return __awaiter(this, void 0, void 0, function* () {
91
137
  if (StockHolderRepository.useMongoose({ eventId: lockKey.eventId, startDate: lockKey.startDate })) {
92
- throw new factory.errors.NotImplemented(`new stock holder repository not implemented for the event '${lockKey.eventId}'`);
138
+ yield this.initializeHoldReservation({ eventId: lockKey.eventId, startDate: lockKey.startDate });
139
+ const addedReservationCount = lockKey.offers.length;
140
+ const subReservations = lockKey.offers.map((offer) => StockHolderRepository.offer2subReservation(offer));
141
+ const reservationPackage = {
142
+ typeOf: factory.reservationType.ReservationPackage,
143
+ reservationNumber: lockKey.holder,
144
+ subReservation: subReservations
145
+ };
146
+ yield this.holdReservationModel.findOneAndUpdate({
147
+ 'reservationFor.id': { $eq: lockKey.eventId },
148
+ // 座席有無に関わらずsubReservation.identifierはuniqueであるはず
149
+ 'reservations.subReservation.identifier': {
150
+ $nin: subReservations.map((r) => r.identifier)
151
+ }
152
+ }, {
153
+ $inc: { reservationCount: addedReservationCount },
154
+ $push: { reservations: reservationPackage }
155
+ }, { new: true })
156
+ .select({ _id: 1 })
157
+ .exec()
158
+ .then((doc) => {
159
+ if (doc === null) {
160
+ throw new factory.errors.AlreadyInUse(factory.reservationType.EventReservation, ['ticketedSeat'], 'Already hold');
161
+ }
162
+ });
93
163
  }
94
164
  else {
95
165
  if (!(lockKey.expires instanceof Date)) {
@@ -144,7 +214,21 @@ class StockHolderRepository {
144
214
  unlock(params) {
145
215
  return __awaiter(this, void 0, void 0, function* () {
146
216
  if (StockHolderRepository.useMongoose({ eventId: params.eventId, startDate: params.startDate })) {
147
- throw new factory.errors.NotImplemented(`new stock holder repository not implemented for the event '${params.eventId}'`);
217
+ // [id]あるいは[seatNumber+seatSection]でreservations.subReservationsから$pull+$incする
218
+ yield this.initializeHoldReservation({ eventId: params.eventId, startDate: params.startDate });
219
+ const subReservation = StockHolderRepository.offer2subReservation(params.offer);
220
+ yield this.holdReservationModel.findOneAndUpdate({
221
+ 'reservationFor.id': { $eq: params.eventId },
222
+ 'reservations.subReservation.identifier': {
223
+ $eq: subReservation.identifier
224
+ }
225
+ }, {
226
+ $inc: { reservationCount: -1 },
227
+ $pull: { 'reservations.subReservation': { identifier: { $eq: subReservation.identifier } } }
228
+ }, { new: true })
229
+ .select({ _id: 1 })
230
+ .exec();
231
+ // docが存在しなくてもよい
148
232
  }
149
233
  else {
150
234
  const key = StockHolderRepository.createKey({ eventId: params.eventId, startDate: params.startDate });
@@ -179,6 +263,7 @@ class StockHolderRepository {
179
263
  countUnavailableOffers(params) {
180
264
  return __awaiter(this, void 0, void 0, function* () {
181
265
  if (StockHolderRepository.useMongoose({ eventId: params.event.id, startDate: params.event.startDate })) {
266
+ // reservationCountを返す
182
267
  return this.holdReservationModel.findOne({
183
268
  'reservationFor.id': { $eq: params.event.id }
184
269
  })
@@ -208,9 +293,40 @@ class StockHolderRepository {
208
293
  * 保持者を取得する
209
294
  */
210
295
  getHolder(params) {
296
+ var _a;
211
297
  return __awaiter(this, void 0, void 0, function* () {
212
298
  if (StockHolderRepository.useMongoose({ eventId: params.eventId, startDate: params.startDate })) {
213
- throw new factory.errors.NotImplemented(`new stock holder repository not implemented for the event '${params.eventId}'`);
299
+ // [id]あるいは[seatNumber+seatSection]でreservationNumberを返す
300
+ yield this.initializeHoldReservation({ eventId: params.eventId, startDate: params.startDate });
301
+ const subReservation = StockHolderRepository.offer2subReservation(params.offer);
302
+ const matchStages = [
303
+ {
304
+ $match: { 'reservationFor.id': { $eq: params.eventId } }
305
+ },
306
+ {
307
+ $match: { 'reservations.subReservation.identifier': { $eq: subReservation.identifier } }
308
+ }
309
+ ];
310
+ const aggregate = this.holdReservationModel.aggregate([
311
+ { $unwind: '$reservations' },
312
+ { $unwind: '$reservations.subReservation' },
313
+ ...matchStages,
314
+ {
315
+ $project: {
316
+ _id: 0,
317
+ reservationNumber: '$reservations.reservationNumber',
318
+ identifier: '$reservations.subReservation.identifier'
319
+ }
320
+ }
321
+ ]);
322
+ const subReservations = yield aggregate.exec();
323
+ debug('getHolder found subReservations.', subReservation.identifier, subReservations);
324
+ if (subReservations.length > 0) {
325
+ return String((_a = subReservations.shift()) === null || _a === void 0 ? void 0 : _a.reservationNumber);
326
+ }
327
+ else {
328
+ return;
329
+ }
214
330
  }
215
331
  else {
216
332
  const key = StockHolderRepository.createKey({ eventId: params.eventId, startDate: params.startDate });
@@ -254,7 +370,37 @@ class StockHolderRepository {
254
370
  searchHolders(params) {
255
371
  return __awaiter(this, void 0, void 0, function* () {
256
372
  if (StockHolderRepository.useMongoose({ eventId: params.eventId, startDate: params.startDate })) {
257
- throw new factory.errors.NotImplemented(`new stock holder repository not implemented for the event '${params.eventId}'`);
373
+ // [id]あるいは[seatNumber+seatSection]のリストでreservationNumberのリストを返す
374
+ yield this.initializeHoldReservation({ eventId: params.eventId, startDate: params.startDate });
375
+ const subReservations = params.offers.map((offer) => StockHolderRepository.offer2subReservation(offer));
376
+ const matchStages = [
377
+ {
378
+ $match: { 'reservationFor.id': { $eq: params.eventId } }
379
+ },
380
+ {
381
+ $match: { 'reservations.subReservation.identifier': { $in: subReservations.map((r) => r.identifier) } }
382
+ }
383
+ ];
384
+ const aggregate = this.holdReservationModel.aggregate([
385
+ { $unwind: '$reservations' },
386
+ { $unwind: '$reservations.subReservation' },
387
+ ...matchStages,
388
+ {
389
+ $project: {
390
+ _id: 0,
391
+ reservationNumber: '$reservations.reservationNumber',
392
+ identifier: '$reservations.subReservation.identifier'
393
+ }
394
+ }
395
+ ]);
396
+ const subReservationsByDoc = yield aggregate.exec();
397
+ return subReservations.map((subReservation) => {
398
+ const subReservationByDoc = subReservationsByDoc.find((r) => r.identifier === subReservation.identifier);
399
+ return (subReservationByDoc !== undefined)
400
+ ? String(subReservationByDoc.reservationNumber)
401
+ // tslint:disable-next-line:no-null-keyword
402
+ : null;
403
+ });
258
404
  }
259
405
  else {
260
406
  const key = StockHolderRepository.createKey({ eventId: params.eventId, startDate: params.startDate });
@@ -318,6 +464,28 @@ class StockHolderRepository {
318
464
  }
319
465
  });
320
466
  }
467
+ initializeHoldReservation(params) {
468
+ return __awaiter(this, void 0, void 0, function* () {
469
+ if (!(params.startDate instanceof Date)) {
470
+ throw new factory.errors.Argument('startDate', 'must be Date');
471
+ }
472
+ const aggregateReservation = {
473
+ typeOf: 'AggregateReservation',
474
+ reservationCount: 0,
475
+ reservationFor: {
476
+ id: params.eventId,
477
+ startDate: params.startDate
478
+ },
479
+ reservations: []
480
+ };
481
+ const initializedHoldReservation = yield this.holdReservationModel.findOneAndUpdate({ 'reservationFor.id': { $eq: params.eventId } }, {
482
+ $setOnInsert: aggregateReservation
483
+ }, { new: true, upsert: true })
484
+ .select({ _id: 1 })
485
+ .exec();
486
+ debug('holdReservation initialized', initializedHoldReservation, params.eventId);
487
+ });
488
+ }
321
489
  }
322
490
  StockHolderRepository.KEY_PREFIX_NEW = 'stockHolder';
323
491
  StockHolderRepository.KEY_PREFIX = 'chevre:itemAvailability:screeningEvent';
package/package.json CHANGED
@@ -117,5 +117,5 @@
117
117
  "postversion": "git push origin --tags",
118
118
  "prepublishOnly": "npm run clean && npm run build && npm test && npm run doc"
119
119
  },
120
- "version": "21.2.0-alpha.119"
120
+ "version": "21.2.0-alpha.120"
121
121
  }