80e4a8bfde9521a2f5274cd5e9c893a1b92930a3 — Martin Angers 4 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 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 @@
 
 // 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 @@
         },
         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 @@
 
   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 @@
   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
+}