@lovebowls/leaguejs
Version:
A framework-agnostic JavaScript library for managing leagues, teams, and matches
170 lines (154 loc) • 5.45 kB
JavaScript
/**
* Match model representing a bowls match between two teams
* @typedef {Object} MatchData
* @property {Object} homeTeam - Home team object with _id property
* @property {Object} awayTeam - Away team object with _id property
* @property {string} [_id] - Unique identifier for the match
* @property {Date|string|null} [date] - Match date (can be null for unscheduled matches)
* @property {number} [rink] - Assigned rink number for the match
* @property {Object} [result] - Optional match result data containing scores
* @property {number} [result.homeScore] - Home team's score
* @property {number} [result.awayScore] - Away team's score
* @property {Array<Object>} [result.rinkScores] - Optional individual rink scores
* @property {Date} [createdAt] - Creation date (defaults to current date)
* @property {Date} [updatedAt] - Last update date (defaults to current date)
*/
import { validateMatch } from '../utils/validators.js';
import { generateGUID } from '../utils/shared.js';
export class Match {
/**
* Create a new Match
* @param {Object} data - Match data
* @param {Object} data.homeTeam - Home team object with _id property
* @param {Object} data.awayTeam - Away team object with _id property
* @param {Date|string|null} [data.date] - Match date (can be null for unscheduled matches)
* @param {number} [data.rink] - Assigned rink number for the match
* @param {Object} [data.result] - Optional match result data containing scores
* @param {number} [data.result.homeScore] - Home team's score
* @param {number} [data.result.awayScore] - Away team's score
* @param {Array<Object>} [data.result.rinkScores] - Optional individual rink scores
* @param {Date} [data.createdAt] - Creation date (defaults to current date)
* @param {Date} [data.updatedAt] - Last update date (defaults to current date)
*/
constructor(data) {
const validationResult = validateMatch(data);
if (!validationResult.isValid) {
throw new Error(validationResult.errors[0]);
}
if (data.homeTeam._id === data.awayTeam._id) {
throw new Error('Home and away teams must be different');
}
this._id = data._id || generateGUID();
this.homeTeam = data.homeTeam;
this.awayTeam = data.awayTeam;
this.date = data.date ? new Date(data.date) : null;
this.rink = data.rink || null;
this.createdAt = data.createdAt || new Date();
this.updatedAt = data.updatedAt || new Date();
// Process result if scores are provided
if (data.result && typeof data.result.homeScore === 'number' && typeof data.result.awayScore === 'number') {
this.result = {
homeScore: data.result.homeScore,
awayScore: data.result.awayScore,
rinkScores: data.result.rinkScores || null
};
} else {
this.result = null; // Ensure result is null if scores are not provided
}
}
/**
* Get the home team name
* @returns {string} - The name of the home team
*/
get homeTeamName() {
return this.homeTeam.name;
}
/**
* Get the away team name
* @returns {string} - The name of the away team
*/
get awayTeamName() {
return this.awayTeam.name;
}
/**
* Determines the winner of the match based on scores.
* @returns {string|null} - The name of the winning team, 'draw', or null if no result is set.
*/
getWinner() {
if (!this.result) {
return null;
}
if (this.result.homeScore > this.result.awayScore) {
return this.homeTeamName;
}
if (this.result.awayScore > this.result.homeScore) {
return this.awayTeamName;
}
return 'draw';
}
/**
* Checks if the match resulted in a draw.
* @returns {boolean|null} - True if it's a draw, false otherwise, or null if no result is set.
*/
isDraw() {
if (!this.result) {
return null;
}
return this.result.homeScore === this.result.awayScore;
}
/**
* Set rink scores for an existing match result
* @param {Array} rinkScores - Array of rink scores [{homeScore, awayScore}, ...]
* @returns {boolean} - True if scores were set, false if no result exists
*/
setRinkScores(rinkScores) {
if (!this.result) return false;
this.result.rinkScores = rinkScores;
this.updatedAt = new Date();
return true;
}
/**
* Get rink win/draw counts
* @returns {Object|null} - Object with rink win counts or null if no rink scores
*/
getRinkResults() {
if (!this.result || !this.result.rinkScores) return null;
const rinkResults = {
homeWins: 0,
awayWins: 0,
draws: 0,
total: this.result.rinkScores.length
};
this.result.rinkScores.forEach(rink => {
if (rink.homeScore > rink.awayScore) {
rinkResults.homeWins++;
} else if (rink.awayScore > rink.homeScore) {
rinkResults.awayWins++;
} else {
rinkResults.draws++;
}
});
return rinkResults;
}
/**
* Convert match to JSON
* @returns {Object} - JSON representation of the match
*/
toJSON() {
const jsonResult = this.result ? {
...this.result,
winner: this.getWinner(),
isDraw: this.isDraw()
} : null;
return {
_id: this._id,
homeTeam: this.homeTeam,
awayTeam: this.awayTeam,
date: this.date,
rink: this.rink,
result: jsonResult,
createdAt: this.createdAt,
updatedAt: this.updatedAt
};
}
}