~mna/hockeysim

80e4a8bfde9521a2f5274cd5e9c893a1b92930a3 — Martin Angers 11 months ago 6136c79
implement season newcommand
M db/migrations/011_seasons.sql => db/migrations/011_seasons.sql +1 -1
@@ 1,7 1,7 @@
CREATE TABLE seasons (
  id        INT UNSIGNED NOT NULL AUTO_INCREMENT,
  league_id INT UNSIGNED NOT NULL,
  year      TINYINT UNSIGNED NOT NULL,
  year      SMALLINT UNSIGNED NOT NULL,
  state     TINYINT UNSIGNED NOT NULL DEFAULT 0, -- 0: unstarted, 1: started, 2: completed
  created   TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated   TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

M src/cmds/season_cmds/new.js => src/cmds/season_cmds/new.js +32 -4
@@ 2,7 2,9 @@ import CFonts from 'cfonts'
import inquirer from 'inquirer'
import { DB } from 'mymigrate'
import { leaguesForNewSeason } from '../../leagues'
// import exec from '../../handlers/season_cmds/new'
import { nextSeasonForLeague } from '../../seasons'
import { Constants } from '../../constants'
import exec from '../../handlers/season_cmds/new'

export const command = 'new'
export const desc = 'Create new season'


@@ 15,7 17,7 @@ export function builder (yargs) {

// TODO: (for all commands) display error if nothing can be selected.

function leagueSelectionQuestion (conn, { league = '' }) {
function questions (conn, { league = '' }) {
  return () => {
    return inquirer.prompt ([
      {


@@ 28,6 30,30 @@ function leagueSelectionQuestion (conn, { league = '' }) {
        },
        pageSize: 10,
      },
      {
        type: 'number',
        name: 'year',
        message: 'Season year:',
        default ({ leagueId }) {
          return nextSeasonForLeague (conn, leagueId)
        },
        validate (input) {
          const year = parseInt (input, 10)
          if (Number.isNaN (year)) {
            return 'invalid number'
          }
          if (year < Constants.minSeasonYear || year > Constants.maxSeasonYear) {
            return `invalid year, must be between ${Constants.minSeasonYear} and ${Constants.maxSeasonYear}`
          }
          return true
        },
      },
      {
        type: 'confirm',
        name: 'confirm',
        message: 'Create this season?',
        default: true,
      },
    ])
  }
}


@@ 40,9 66,11 @@ export async function handler (argv) {

  const conn = await new DB ().connect ()
  try {
    const prompt = leagueSelectionQuestion (conn, argv)
    const prompt = questions (conn, argv)
    const res = await prompt ()
    console.log (res)
    if (res.confirm) {
      await exec (conn, res)
    }
  } finally {
    await conn.end ()
  }

M src/constants.js => src/constants.js +2 -0
@@ 2,6 2,8 @@ const Constants = Object.freeze ({
  teamsPerLeague: 12,
  maxLeagueNameLength: 100,
  maxTeamNameLength: 100,
  minSeasonYear: 1900,
  maxSeasonYear: 2999,
})

const PlayerName = Object.freeze ({

A src/handlers/season_cmds/new.js => src/handlers/season_cmds/new.js +5 -0
@@ 0,0 1,5 @@
import { createSeason } from '../../seasons'

export default async function (conn, { leagueId, year } = {}) {
  await createSeason (conn, leagueId, year)
}

A src/seasons.js => src/seasons.js +21 -0
@@ 0,0 1,21 @@
import { SeasonState } from './constants'

export async function nextSeasonForLeague (conn, leagueId) {
  const [res] = await conn.query (`
    select max(year) as last
    from   seasons
    where  league_id = ?
  `, [leagueId])

  if (res.length > 0 && res[0].last) {
    return res[0].last + 1
  }
  return 0
}

// creates a new season and returns the ID
export async function createSeason (conn, leagueId, year, state = SeasonState.unstarted) {
  // TODO: should validate atomically that there is no other unstarted/active season
  const [res] = await conn.query ('insert into seasons (league_id, year, state) values (?, ?, ?)', [leagueId, year, state])
  return res.insertId
}