dbmedialab/reader-critics

View on GitHub
src/app/services/feedback/dao/feedbackStatus.ts

Summary

Maintainability
A
0 mins
Test Coverage
//
// LESERKRITIKK v2 (aka Reader Critics)
// Copyright (C) 2017 DB Medialab/Aller Media AS, Oslo, Norway
// https://github.com/dbmedialab/reader-critics/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.
//

import Feedback from 'base/Feedback';
import FeedbackStatus from 'base/FeedbackStatus';
import emptyCheck from 'app/util/emptyCheck';

import { FeedbackModel } from 'app/db/models';
import { wrapFindOne } from 'app/db/common';
import { ModelFindByIdAndUpdateOptions } from 'mongoose';

export function updateStatus(
    feedback : Feedback,
    newStatus : FeedbackStatus
) : Promise <void>
{
    emptyCheck(feedback, newStatus);

    // Need to load the feedback object first for pushing its current status
    // back into its log array. Don't rely on whatever comes in through the
    // "feedback" parameter to this function, it might be outdated, modified,
    // not correctly populated, just don't.
    // I'm afraid this isn't an atomic operation either since MongoDB does not
    // really support document locks, but it's much closer to the ideal.
    return wrapFindOne(FeedbackModel.findOne({
        _id: feedback.ID,
    }))
    // Now findByIdAndUpdate(), move current status to log, set the new one
    .then((fbBefore : Feedback) => {
        const {
            status,
            changeDate,
        } = fbBefore.status;

        const update = {
            // Move current status to log ...
            '$push': {
                'status.log': {
                    status,
                    changeDate,
                },
            },
            // ... and set the new one
            '$set': {
                'status.status': newStatus.toString(),
                'status.changeDate': new Date(),
            },
        };

        const options : ModelFindByIdAndUpdateOptions = {
            // Options! We do not want upsert, fail if it doesn't exist!
            // Impossible by the way, because of the preceeding findOne().
            upsert: false,
        };

        return FeedbackModel.findByIdAndUpdate(feedback.ID, update, options);
    })
    // Ignoring whatever comes from findByIdAndUpdate(), we just return a void
    // promise here. TypeScript is giving me enormous trouble because it insists
    // on the type of the object returned from findByIdAndUpdate() is incompatible
    // with the "Feedback" interface, even when wrapping it with wrapFindOne().
    // Since the modified object is (at least I think so right now) not needed
    // inside the application and it just would have been convenient for the tests
    // I decided to give up and just return Promise <void> instead.
    // If need be, chain another getByID() here.
    .then(() => {
        return null;
    });
}