350 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
const path = require("path");
 | 
						|
 | 
						|
const Winner = require(path.join(__dirname, "/schemas/Highscore"));
 | 
						|
const wineRepository = require(path.join(__dirname, "/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;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// highscore
 | 
						|
const addWinnerWithWine = async (winner, wine) => {
 | 
						|
  const exisitingWinner = await Winner.findOne({
 | 
						|
    name: winner.name
 | 
						|
  });
 | 
						|
  const savedWine = await wineRepository.addWine(wine);
 | 
						|
 | 
						|
  const date = new Date();
 | 
						|
  date.setHours(5, 0, 0, 0);
 | 
						|
  const winObject = {
 | 
						|
    date: date,
 | 
						|
    wine: savedWine,
 | 
						|
    color: winner.color
 | 
						|
  };
 | 
						|
 | 
						|
  if (exisitingWinner == undefined) {
 | 
						|
    const newWinner = new Winner({
 | 
						|
      name: winner.name,
 | 
						|
      wins: [winObject]
 | 
						|
    });
 | 
						|
 | 
						|
    await newWinner.save();
 | 
						|
  } else {
 | 
						|
    exisitingWinner.wins.push(winObject);
 | 
						|
    exisitingWinner.markModified("wins");
 | 
						|
    await exisitingWinner.save();
 | 
						|
  }
 | 
						|
 | 
						|
  return exisitingWinner;
 | 
						|
};
 | 
						|
 | 
						|
// lottery
 | 
						|
const all = (includeWines = false) => {
 | 
						|
  if (includeWines === false) {
 | 
						|
    return Winner.find().sort("-wins.date");
 | 
						|
  } else {
 | 
						|
    return Winner.find()
 | 
						|
      .sort("-wins.date")
 | 
						|
      .populate("wins.wine");
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
// lottery
 | 
						|
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;
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
// highscore
 | 
						|
const byName = (name, sort = "desc") => {
 | 
						|
  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();
 | 
						|
      }
 | 
						|
    });
 | 
						|
};
 | 
						|
 | 
						|
// highscore
 | 
						|
const search = (query, sort = "desc") => {
 | 
						|
  return Winner.find({ name: { $regex: query, $options: "i" } }, ["name"]).then(winners => {
 | 
						|
    if (winners) {
 | 
						|
      winners = sort === "desc" ? winners.reverse() : winners;
 | 
						|
      return winners;
 | 
						|
    } else {
 | 
						|
      throw new HistoryForUserNotFound();
 | 
						|
    }
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
// lottery
 | 
						|
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]);
 | 
						|
};
 | 
						|
 | 
						|
// lottery - byDate
 | 
						|
const groupByDate = (includeWines = false, sort = "asc") => {
 | 
						|
  const sortDirection = sort == "asc" ? -1 : 1;
 | 
						|
  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: {
 | 
						|
        date: sortDirection
 | 
						|
      }
 | 
						|
    }
 | 
						|
  ];
 | 
						|
 | 
						|
  if (includeWines) {
 | 
						|
    query.splice(1, 0, {
 | 
						|
      $lookup: {
 | 
						|
        from: "wines",
 | 
						|
        localField: "wins.wine",
 | 
						|
        foreignField: "_id",
 | 
						|
        as: "wins.wine"
 | 
						|
      }
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  return Winner.aggregate(query);
 | 
						|
};
 | 
						|
 | 
						|
// highscore - byColor
 | 
						|
const groupByColor = (includeWines = false) => {
 | 
						|
  const query = [
 | 
						|
    {
 | 
						|
      $unwind: "$wins"
 | 
						|
    },
 | 
						|
    {
 | 
						|
      $group: {
 | 
						|
        _id: "$wins.color",
 | 
						|
        winners: {
 | 
						|
          $push: {
 | 
						|
            _id: "$_id",
 | 
						|
            name: "$name",
 | 
						|
            date: "$wins.date",
 | 
						|
            wine: "$wins.wine"
 | 
						|
          }
 | 
						|
        },
 | 
						|
        count: { $sum: 1 }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    {
 | 
						|
      $project: {
 | 
						|
        color: "$_id",
 | 
						|
        count: "$count",
 | 
						|
        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);
 | 
						|
};
 | 
						|
 | 
						|
// highscore - byWineOccurences
 | 
						|
 | 
						|
// highscore - byWinCount
 | 
						|
const orderByWins = (includeWines = false, limit = undefined) => {
 | 
						|
  let query = [
 | 
						|
    {
 | 
						|
      $project: {
 | 
						|
        name: "$name",
 | 
						|
        wins: "$wins",
 | 
						|
        totalWins: { $size: "$wins" }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    {
 | 
						|
      $sort: {
 | 
						|
        totalWins: -1,
 | 
						|
        "wins.date": -1
 | 
						|
      }
 | 
						|
    }
 | 
						|
  ];
 | 
						|
 | 
						|
  if (includeWines) {
 | 
						|
    const includeWinesSubQuery = [
 | 
						|
      {
 | 
						|
        $unwind: "$wins"
 | 
						|
      },
 | 
						|
      {
 | 
						|
        $lookup: {
 | 
						|
          from: "wines",
 | 
						|
          localField: "wins.wine",
 | 
						|
          foreignField: "_id",
 | 
						|
          as: "wins.wine"
 | 
						|
        }
 | 
						|
      },
 | 
						|
      {
 | 
						|
        $unwind: "$wins._id"
 | 
						|
      },
 | 
						|
      {
 | 
						|
        $group: {
 | 
						|
          _id: "$_id",
 | 
						|
          name: { $first: "$name" },
 | 
						|
          totalWins: { $first: "$totalWins" },
 | 
						|
          wins: { $push: "$wins" }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    ];
 | 
						|
 | 
						|
    query = includeWinesSubQuery.concat(query);
 | 
						|
  }
 | 
						|
 | 
						|
  return Winner.aggregate(query).then(winners => {
 | 
						|
    if (limit == null) {
 | 
						|
      return winners;
 | 
						|
    }
 | 
						|
 | 
						|
    return winners.slice(0, limit);
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
module.exports = {
 | 
						|
  addWinnerWithWine,
 | 
						|
  all,
 | 
						|
  byDate,
 | 
						|
  byName,
 | 
						|
  search,
 | 
						|
  latest,
 | 
						|
  groupByDate,
 | 
						|
  groupByColor,
 | 
						|
  orderByWins
 | 
						|
};
 |