Source: repo/itemAvailability/screeningEvent.js

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const createDebug = require("debug");
const moment = require("moment");
const factory = require("../../factory");
const debug = createDebug('chevre-domain:repo');
/**
 * 上映イベントに対する座席ごとの在庫状況を保管するリポジトリ
 */
class RedisRepository {
    constructor(redisClient) {
        this.redisClient = redisClient;
    }
    /**
     * 座席をロックする
     */
    lock(lockKey) {
        return __awaiter(this, void 0, void 0, function* () {
            debug('locking...', lockKey);
            const key = `${RedisRepository.KEY_PREFIX}:${lockKey.eventId}`;
            const value = lockKey.holder;
            const multi = this.redisClient.multi();
            const fields = lockKey.offers.map((offer) => `${offer.seatSection}:${offer.seatNumber}`);
            fields.forEach((field) => {
                multi.hsetnx(key, field, value);
            });
            const results = yield new Promise((resolve, reject) => {
                multi.expireat(key, moment(lockKey.expires).unix())
                    .exec((err, reply) => {
                    debug('reply:', reply);
                    if (err !== null) {
                        reject(err);
                    }
                    else {
                        resolve(reply);
                    }
                });
            });
            const lockedFields = [];
            results.slice(0, fields.length).forEach((r, index) => {
                if (r === 1) {
                    lockedFields.push(fields[index]);
                }
            });
            debug('locked fields:', lockedFields);
            const lockedAll = lockedFields.length === fields.length;
            debug('lockedAll?', lockedAll);
            if (!lockedAll) {
                if (lockedFields.length > 0) {
                    // 全て仮押さえできなければ仮押さえできたものは解除
                    yield new Promise((resolve, reject) => {
                        this.redisClient.multi()
                            .hdel(key, lockedFields)
                            .exec((err, reply) => {
                            debug('reply:', reply);
                            if (err !== null) {
                                reject(err);
                            }
                            else {
                                resolve();
                            }
                        });
                    });
                }
                throw new factory.errors.AlreadyInUse('', [], 'Seat number already hold');
            }
        });
    }
    /**
     * 座席ロックを解除する
     */
    unlock(params) {
        return __awaiter(this, void 0, void 0, function* () {
            const key = `${RedisRepository.KEY_PREFIX}:${params.eventId}`;
            const field = `${params.offer.seatSection}:${params.offer.seatNumber}`;
            yield new Promise((resolve, reject) => {
                this.redisClient.multi()
                    .hdel(key, field)
                    .exec((err, reply) => {
                    debug('reply:', reply);
                    if (err !== null) {
                        reject(err);
                    }
                    else {
                        resolve();
                    }
                });
            });
        });
    }
    /**
     * 空席でない座席を検索する
     */
    findUnavailableOffersByEventId(params) {
        return __awaiter(this, void 0, void 0, function* () {
            const key = `${RedisRepository.KEY_PREFIX}:${params.eventId}`;
            return new Promise((resolve, reject) => {
                this.redisClient.hgetall(key, (err, reply) => {
                    debug('reply:', reply);
                    if (err !== null) {
                        reject(err);
                    }
                    else {
                        let offers = [];
                        if (reply !== null) {
                            offers = Object.keys(reply).map((field) => {
                                const seatSection = field.split(':')[0];
                                const seatNumber = field.split(':')[1];
                                return { seatSection, seatNumber };
                            });
                        }
                        resolve(offers);
                    }
                });
            });
        });
    }
    /**
     * 保持者を取得する
     */
    getHolder(params) {
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const key = `${RedisRepository.KEY_PREFIX}:${params.eventId}`;
                const field = `${params.offer.seatSection}:${params.offer.seatNumber}`;
                this.redisClient.hget(key, field, (err, result) => {
                    debug('result:', err, result);
                    if (err !== null) {
                        reject(err);
                    }
                    else {
                        // tslint:disable-next-line:no-magic-numbers
                        resolve(result);
                    }
                });
            });
        });
    }
}
RedisRepository.KEY_PREFIX = 'chevre:itemAvailability:screeningEvent';
exports.RedisRepository = RedisRepository;