Renamed to winners. Winners gets controller setup.
Rewrote everything that happened in history to better take advantage of monogdb instead of doing everything in js. Our endpoints become: - /winners - getAll w/ includeWines and sort query params. - /winners/latest - latest winners grouped w/ includeWines query params. - /winners/by-date - all winners grouped by date w/ includeWines and sort. - /winners/by-date/:date - get winners per epoch or string date. - /winners/by-name/:name - get winner by name parameter w/ sort for wins direction.
This commit is contained in:
		@@ -1,92 +0,0 @@
 | 
				
			|||||||
const path = require("path");
 | 
					 | 
				
			||||||
const historyRepository = require(path.join(__dirname, "../history"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const all = (req, res) => {
 | 
					 | 
				
			||||||
  return historyRepository
 | 
					 | 
				
			||||||
    .all()
 | 
					 | 
				
			||||||
    .then(lotteries =>
 | 
					 | 
				
			||||||
      res.send({
 | 
					 | 
				
			||||||
        lotteries: lotteries,
 | 
					 | 
				
			||||||
        success: true
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    .catch(error => {
 | 
					 | 
				
			||||||
      const { statusCode, message } = error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return res.status(statusCode || 500).send({
 | 
					 | 
				
			||||||
        success: false,
 | 
					 | 
				
			||||||
        message: message || "Unable to fetch history."
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const latest = (req, res) => {
 | 
					 | 
				
			||||||
  return historyRepository
 | 
					 | 
				
			||||||
    .latest()
 | 
					 | 
				
			||||||
    .then(lottery =>
 | 
					 | 
				
			||||||
      res.send({
 | 
					 | 
				
			||||||
        lottery: lottery,
 | 
					 | 
				
			||||||
        success: true
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    .catch(error => {
 | 
					 | 
				
			||||||
      const { statusCode, message } = error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return res.status(statusCode || 500).send({
 | 
					 | 
				
			||||||
        success: false,
 | 
					 | 
				
			||||||
        message: message || "Unable to fetch latest history."
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const byDate = (req, res) => {
 | 
					 | 
				
			||||||
  let { date } = req.params;
 | 
					 | 
				
			||||||
  date = new Date(new Date(parseInt(date)).setHours(0, 0, 0, 0)).getTime();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return historyRepository
 | 
					 | 
				
			||||||
    .byEpochDate(date)
 | 
					 | 
				
			||||||
    .then(winners =>
 | 
					 | 
				
			||||||
      res.send({
 | 
					 | 
				
			||||||
        date: date,
 | 
					 | 
				
			||||||
        winners: winners,
 | 
					 | 
				
			||||||
        success: true
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    .catch(error => {
 | 
					 | 
				
			||||||
      const { statusCode, message } = error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return res.status(statusCode || 500).send({
 | 
					 | 
				
			||||||
        success: false,
 | 
					 | 
				
			||||||
        message: message || "Unable to fetch history for date."
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const byName = (req, res) => {
 | 
					 | 
				
			||||||
  const { name } = req.params;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return historyRepository
 | 
					 | 
				
			||||||
    .byName(name)
 | 
					 | 
				
			||||||
    .then(lotteries =>
 | 
					 | 
				
			||||||
      res.send({
 | 
					 | 
				
			||||||
        name: name,
 | 
					 | 
				
			||||||
        lotteries: lotteries,
 | 
					 | 
				
			||||||
        success: true
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    .catch(error => {
 | 
					 | 
				
			||||||
      const { statusCode, message } = error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return res.status(statusCode || 500).send({
 | 
					 | 
				
			||||||
        success: false,
 | 
					 | 
				
			||||||
        message: message || "Unable to fetch history for name."
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = {
 | 
					 | 
				
			||||||
  all,
 | 
					 | 
				
			||||||
  latest,
 | 
					 | 
				
			||||||
  byDate,
 | 
					 | 
				
			||||||
  byName
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										165
									
								
								api/controllers/winnerController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								api/controllers/winnerController.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					const path = require("path");
 | 
				
			||||||
 | 
					const winnerRepository = require(path.join(__dirname, "../winner"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const sortOptions = ["desc", "asc"];
 | 
				
			||||||
 | 
					const includeWinesOptions = ["true", "false"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const all = (req, res) => {
 | 
				
			||||||
 | 
					  let { sort, includeWines } = req.query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (sort !== undefined && !sortOptions.includes(sort)) {
 | 
				
			||||||
 | 
					    return res.status(400).send({
 | 
				
			||||||
 | 
					      message: `Sort option must be: '${sortOptions.join(", ")}'`,
 | 
				
			||||||
 | 
					      success: false
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (includeWines !== undefined && !includeWinesOptions.includes(includeWines)) {
 | 
				
			||||||
 | 
					    return res.status(400).send({
 | 
				
			||||||
 | 
					      message: `includeWines option must be: '${includeWinesOptions.join(", ")}'`,
 | 
				
			||||||
 | 
					      success: false
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return winnerRepository
 | 
				
			||||||
 | 
					    .all(includeWines == "true")
 | 
				
			||||||
 | 
					    .then(winners =>
 | 
				
			||||||
 | 
					      res.send({
 | 
				
			||||||
 | 
					        winners: sort !== "asc" ? winners : winners.reverse(),
 | 
				
			||||||
 | 
					        success: true
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .catch(error => {
 | 
				
			||||||
 | 
					      const { statusCode, message } = error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return res.status(statusCode || 500).send({
 | 
				
			||||||
 | 
					        success: false,
 | 
				
			||||||
 | 
					        message: message || "Unable to fetch winners."
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const byDate = (req, res) => {
 | 
				
			||||||
 | 
					  let { date } = req.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const regexDate = new RegExp("^\\d{4}-\\d{2}-\\d{2}$");
 | 
				
			||||||
 | 
					  if (!isNaN(date)) {
 | 
				
			||||||
 | 
					    date = new Date(new Date(parseInt(date * 1000)).setHours(0, 0, 0, 0));
 | 
				
			||||||
 | 
					  } else if (regexDate.test(date)) {
 | 
				
			||||||
 | 
					    date = new Date(date);
 | 
				
			||||||
 | 
					  } else if (date !== undefined) {
 | 
				
			||||||
 | 
					    return res.status(400).send({
 | 
				
			||||||
 | 
					      message: "Invalid date parameter, allowed epoch seconds or YYYY-MM-DD.",
 | 
				
			||||||
 | 
					      success: false
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return winnerRepository
 | 
				
			||||||
 | 
					    .byDate(date)
 | 
				
			||||||
 | 
					    .then(winners =>
 | 
				
			||||||
 | 
					      res.send({
 | 
				
			||||||
 | 
					        date: date,
 | 
				
			||||||
 | 
					        winners: winners,
 | 
				
			||||||
 | 
					        success: true
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .catch(error => {
 | 
				
			||||||
 | 
					      const { statusCode, message } = error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return res.status(statusCode || 500).send({
 | 
				
			||||||
 | 
					        success: false,
 | 
				
			||||||
 | 
					        message: message || "Unable to fetch winner by date."
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const groupedByDate = (req, res) => {
 | 
				
			||||||
 | 
					  let { sort, includeWines } = req.query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (sort !== undefined && !sortOptions.includes(sort)) {
 | 
				
			||||||
 | 
					    return res.status(400).send({
 | 
				
			||||||
 | 
					      message: `Sort option must be: '${sortOptions.join(", ")}'`,
 | 
				
			||||||
 | 
					      success: false
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (includeWines !== undefined && !includeWinesOptions.includes(includeWines)) {
 | 
				
			||||||
 | 
					    return res.status(400).send({
 | 
				
			||||||
 | 
					      message: `includeWines option must be: '${includeWinesOptions.join(", ")}'`,
 | 
				
			||||||
 | 
					      success: false
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return winnerRepository
 | 
				
			||||||
 | 
					    .groupedByDate(includeWines, sort)
 | 
				
			||||||
 | 
					    .then(lotteries =>
 | 
				
			||||||
 | 
					      res.send({
 | 
				
			||||||
 | 
					        lotteries: lotteries,
 | 
				
			||||||
 | 
					        success: true
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .catch(error => {
 | 
				
			||||||
 | 
					      const { statusCode, message } = error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return res.status(statusCode || 500).send({
 | 
				
			||||||
 | 
					        success: false,
 | 
				
			||||||
 | 
					        message: message || "Unable to fetch winner by date."
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const latest = (req, res) => {
 | 
				
			||||||
 | 
					  return winnerRepository
 | 
				
			||||||
 | 
					    .latest()
 | 
				
			||||||
 | 
					    .then(winners =>
 | 
				
			||||||
 | 
					      res.send({
 | 
				
			||||||
 | 
					        ...winners,
 | 
				
			||||||
 | 
					        success: true
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .catch(error => {
 | 
				
			||||||
 | 
					      const { statusCode, message } = error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return res.status(statusCode || 500).send({
 | 
				
			||||||
 | 
					        success: false,
 | 
				
			||||||
 | 
					        message: message || "Unable to fetch winner by date."
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const byName = (req, res) => {
 | 
				
			||||||
 | 
					  const { name } = req.params;
 | 
				
			||||||
 | 
					  const { sort } = req.query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (sort !== undefined && !sortOptions.includes(sort)) {
 | 
				
			||||||
 | 
					    return res.status(400).send({
 | 
				
			||||||
 | 
					      message: `Sort option must be: '${sortOptions.join(", ")}'`,
 | 
				
			||||||
 | 
					      success: false
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return winnerRepository
 | 
				
			||||||
 | 
					    .byName(name, sort)
 | 
				
			||||||
 | 
					    .then(winner =>
 | 
				
			||||||
 | 
					      res.send({
 | 
				
			||||||
 | 
					        winner: winner,
 | 
				
			||||||
 | 
					        success: true
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .catch(error => {
 | 
				
			||||||
 | 
					      const { statusCode, message } = error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return res.status(statusCode || 500).send({
 | 
				
			||||||
 | 
					        success: false,
 | 
				
			||||||
 | 
					        message: message || "Unable to fetch winner by name."
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  all,
 | 
				
			||||||
 | 
					  byDate,
 | 
				
			||||||
 | 
					  groupedByDate,
 | 
				
			||||||
 | 
					  latest,
 | 
				
			||||||
 | 
					  byName
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										117
									
								
								api/history.js
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								api/history.js
									
									
									
									
									
								
							@@ -1,117 +0,0 @@
 | 
				
			|||||||
const path = require("path");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const Highscore = require(path.join(__dirname, "/schemas/Highscore"));
 | 
					 | 
				
			||||||
const Wine = require(path.join(__dirname, "/schemas/Wine"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class HistoryByDateNotFound extends Error {
 | 
					 | 
				
			||||||
  constructor(message = "History for given date not found.") {
 | 
					 | 
				
			||||||
    super(message);
 | 
					 | 
				
			||||||
    this.name = "HistoryByDateNotFound";
 | 
					 | 
				
			||||||
    this.statusCode = 404;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class HistoryForUserNotFound extends Error {
 | 
					 | 
				
			||||||
  constructor(message = "History for given user not found.") {
 | 
					 | 
				
			||||||
    super(message);
 | 
					 | 
				
			||||||
    this.name = "HistoryForUserNotFound";
 | 
					 | 
				
			||||||
    this.statusCode = 404;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Utils
 | 
					 | 
				
			||||||
const epochToDateString = date => new Date(parseInt(date)).toDateString();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const sortNewestFirst = lotteries => {
 | 
					 | 
				
			||||||
  return lotteries.sort((a, b) => (parseInt(a.date) < parseInt(b.date) ? 1 : -1));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const groupHighscoreByDate = async (highscore = undefined) => {
 | 
					 | 
				
			||||||
  if (highscore == undefined) highscore = await Highscore.find();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const highscoreByDate = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  highscore.forEach(person => {
 | 
					 | 
				
			||||||
    person.wins.map(win => {
 | 
					 | 
				
			||||||
      const epochDate = new Date(win.date).setHours(0, 0, 0, 0);
 | 
					 | 
				
			||||||
      const winnerObject = {
 | 
					 | 
				
			||||||
        name: person.name,
 | 
					 | 
				
			||||||
        color: win.color,
 | 
					 | 
				
			||||||
        wine: win.wine,
 | 
					 | 
				
			||||||
        date: epochDate
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const existingDateIndex = highscoreByDate.findIndex(el => el.date == epochDate);
 | 
					 | 
				
			||||||
      if (existingDateIndex > -1) highscoreByDate[existingDateIndex].winners.push(winnerObject);
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        highscoreByDate.push({
 | 
					 | 
				
			||||||
          date: epochDate,
 | 
					 | 
				
			||||||
          winners: [winnerObject]
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return sortNewestFirst(highscoreByDate);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const resolveWineReferences = (highscoreObject, key) => {
 | 
					 | 
				
			||||||
  const listWithWines = highscoreObject[key];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return Promise.all(
 | 
					 | 
				
			||||||
    listWithWines.map(element =>
 | 
					 | 
				
			||||||
      Wine.findById(element.wine).then(wine => {
 | 
					 | 
				
			||||||
        element.wine = wine;
 | 
					 | 
				
			||||||
        return element;
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  ).then(resolvedListWithWines => {
 | 
					 | 
				
			||||||
    highscoreObject[key] = resolvedListWithWines;
 | 
					 | 
				
			||||||
    return highscoreObject;
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
// end utils
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Routes
 | 
					 | 
				
			||||||
const all = () => {
 | 
					 | 
				
			||||||
  return Highscore.find().then(highscore => groupHighscoreByDate(highscore));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const latest = () => {
 | 
					 | 
				
			||||||
  return groupHighscoreByDate()
 | 
					 | 
				
			||||||
    .then(lotteries => lotteries.shift()) // first element in list
 | 
					 | 
				
			||||||
    .then(latestLottery => resolveWineReferences(latestLottery, "winners"));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const byEpochDate = date => {
 | 
					 | 
				
			||||||
  return groupHighscoreByDate()
 | 
					 | 
				
			||||||
    .then(lotteries => {
 | 
					 | 
				
			||||||
      const lottery = lotteries.filter(lottery => lottery.date == date);
 | 
					 | 
				
			||||||
      if (lottery.length > 0) {
 | 
					 | 
				
			||||||
        return lottery[0];
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        throw new HistoryByDateNotFound();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    .then(lottery => resolveWineReferences(lottery, "winners"))
 | 
					 | 
				
			||||||
    .then(lottery => lottery.winners);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const byName = name => {
 | 
					 | 
				
			||||||
  return Highscore.find({ name })
 | 
					 | 
				
			||||||
    .then(highscore => {
 | 
					 | 
				
			||||||
      if (highscore.length > 0) {
 | 
					 | 
				
			||||||
        return highscore[0];
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        throw new HistoryForUserNotFound();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    .then(highscore => resolveWineReferences(highscore, "wins"))
 | 
					 | 
				
			||||||
    .then(highscore => sortNewestFirst(highscore.wins));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = {
 | 
					 | 
				
			||||||
  all,
 | 
					 | 
				
			||||||
  latest,
 | 
					 | 
				
			||||||
  byEpochDate,
 | 
					 | 
				
			||||||
  byName
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										191
									
								
								api/winner.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								api/winner.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
				
			|||||||
 | 
					const path = require("path");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Winner = require(path.join(__dirname, "/schemas/Highscore"));
 | 
				
			||||||
 | 
					const Wine = require(path.join(__dirname, "/schemas/Wine"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HistoryByDateNotFound extends Error {
 | 
				
			||||||
 | 
					  constructor(message = "History for given date not found.") {
 | 
				
			||||||
 | 
					    super(message);
 | 
				
			||||||
 | 
					    this.name = "HistoryByDateNotFound";
 | 
				
			||||||
 | 
					    this.statusCode = 404;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HistoryForUserNotFound extends Error {
 | 
				
			||||||
 | 
					  constructor(message = "History for given user not found.") {
 | 
				
			||||||
 | 
					    super(message);
 | 
				
			||||||
 | 
					    this.name = "HistoryForUserNotFound";
 | 
				
			||||||
 | 
					    this.statusCode = 404;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const all = (includeWines = false) => {
 | 
				
			||||||
 | 
					  if (includeWines === false) {
 | 
				
			||||||
 | 
					    return Winner.find().sort("-wins.date");
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return Winner.find()
 | 
				
			||||||
 | 
					      .sort("-wins.date")
 | 
				
			||||||
 | 
					      .populate("wins.wine");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const byDate = date => {
 | 
				
			||||||
 | 
					  const startQueryDate = new Date(date.setHours(0, 0, 0, 0));
 | 
				
			||||||
 | 
					  const endQueryDate = new Date(date.setHours(24, 59, 59, 99));
 | 
				
			||||||
 | 
					  const query = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $match: {
 | 
				
			||||||
 | 
					        "wins.date": {
 | 
				
			||||||
 | 
					          $gte: startQueryDate,
 | 
				
			||||||
 | 
					          $lte: endQueryDate
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { $unwind: "$wins" },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $match: {
 | 
				
			||||||
 | 
					        "wins.date": {
 | 
				
			||||||
 | 
					          $gte: startQueryDate,
 | 
				
			||||||
 | 
					          $lte: endQueryDate
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $lookup: {
 | 
				
			||||||
 | 
					        from: "wines",
 | 
				
			||||||
 | 
					        localField: "wins.wine",
 | 
				
			||||||
 | 
					        foreignField: "_id",
 | 
				
			||||||
 | 
					        as: "wins.wine"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { $unwind: "$wins.wine" },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $project: {
 | 
				
			||||||
 | 
					        name: "$name",
 | 
				
			||||||
 | 
					        date: "$wins.date",
 | 
				
			||||||
 | 
					        color: "$wins.color",
 | 
				
			||||||
 | 
					        wine: "$wins.wine"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Winner.aggregate(query).then(winners => {
 | 
				
			||||||
 | 
					    if (winners.length == 0) {
 | 
				
			||||||
 | 
					      throw new HistoryByDateNotFound();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return winners;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const byName = (name, sort = "desc") => {
 | 
				
			||||||
 | 
					  const populateOptions = { sort: "date" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Winner.findOne({ name }, ["name", "wins"])
 | 
				
			||||||
 | 
					    .sort("-wins.date")
 | 
				
			||||||
 | 
					    .populate("wins.wine")
 | 
				
			||||||
 | 
					    .then(winner => {
 | 
				
			||||||
 | 
					      if (winner) {
 | 
				
			||||||
 | 
					        winner.wins = sort !== "asc" ? winner.wins.reverse() : winner.wins;
 | 
				
			||||||
 | 
					        return winner;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        throw new HistoryForUserNotFound();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const latest = () => {
 | 
				
			||||||
 | 
					  const query = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $unwind: "$wins"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $lookup: {
 | 
				
			||||||
 | 
					        from: "wines",
 | 
				
			||||||
 | 
					        localField: "wins.wine",
 | 
				
			||||||
 | 
					        foreignField: "_id",
 | 
				
			||||||
 | 
					        as: "wins.wine"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $group: {
 | 
				
			||||||
 | 
					        _id: "$wins.date",
 | 
				
			||||||
 | 
					        winners: {
 | 
				
			||||||
 | 
					          $push: {
 | 
				
			||||||
 | 
					            _id: "$_id",
 | 
				
			||||||
 | 
					            name: "$name",
 | 
				
			||||||
 | 
					            color: "$wins.color",
 | 
				
			||||||
 | 
					            wine: "$wins.wine"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $project: {
 | 
				
			||||||
 | 
					        date: "$_id",
 | 
				
			||||||
 | 
					        winners: "$winners"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $sort: {
 | 
				
			||||||
 | 
					        _id: -1
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $limit: 1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Winner.aggregate(query).then(winners => winners[0]);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const groupedByDate = (includeWines = false, sort = "desc") => {
 | 
				
			||||||
 | 
					  const query = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $unwind: "$wins"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $group: {
 | 
				
			||||||
 | 
					        _id: "$wins.date",
 | 
				
			||||||
 | 
					        winners: {
 | 
				
			||||||
 | 
					          $push: {
 | 
				
			||||||
 | 
					            _id: "$_id",
 | 
				
			||||||
 | 
					            name: "$name",
 | 
				
			||||||
 | 
					            color: "$wins.color",
 | 
				
			||||||
 | 
					            wine: "$wins.wine"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $project: {
 | 
				
			||||||
 | 
					        date: "$_id",
 | 
				
			||||||
 | 
					        winners: "$winners"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      $sort: {
 | 
				
			||||||
 | 
					        _id: -1
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (includeWines) {
 | 
				
			||||||
 | 
					    query.splice(1, 0, {
 | 
				
			||||||
 | 
					      $lookup: {
 | 
				
			||||||
 | 
					        from: "wines",
 | 
				
			||||||
 | 
					        localField: "wins.wine",
 | 
				
			||||||
 | 
					        foreignField: "_id",
 | 
				
			||||||
 | 
					        as: "wins.wine"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Winner.aggregate(query).then(lotteries => (sort != "asc" ? lotteries : lotteries.reverse()));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  all,
 | 
				
			||||||
 | 
					  byDate,
 | 
				
			||||||
 | 
					  latest,
 | 
				
			||||||
 | 
					  groupedByDate
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
		Reference in New Issue
	
	Block a user