workouttracker/workout.sh

359 lines
6.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# TODO: enforce machine to routine consistency
# (maybe with a TRIGGER on the routine
# column in the machine table and a
# matching EXCLUDE constraint?)
#
# as a bonus, this would allow easily
# changing machines between routines
### variable definitions
## tui
# prompts
selectprompt="
Your selection: "
dateselectprompt="Enter the date as shown: "
weightprompt="Enter the weight in Kg: "
repsprompt="Enter the number of repititions: "
newmachineprompt="Enter name of new machine: "
newroutineprompt="Enter name of new routine: "
# menus
routinemenu="To begin, you must select your routine
"
machinemenu="
And now select the machine
"
datemenu="
What date do you want to choose?
"
repeatviewreadmenu="
Would you like to enter another mode?
(y/N)"
repeatmachinemenu="
Would you like to select another machine?
(y/N)"
repeatweightmenu="
Would you like to select another weight?
(y/N)"
repeatrepsmenu="
Would you like to add another set?
(y/N)"
vieworlogmenu="
Would you like to view your previous workouts,
or would you like to begin logging sets?
(1) View Previous Workouts.
(2) Begin Logging."
onlydatedmenu="
Would you like to view all from a
certain day, or all previous sets?
(1) All sets
(2) Sets worked on a specific day"
## enviromental
: ${dbname=workouts} # default database name
currentdate=$(date --iso)
### function definitions
## database
# reading
query() {
local command="$1"; shift
case $command in
machines)
psql -tAd ${dbname} <<<"
SELECT name
FROM machine
WHERE routine='${routine[$workingroutine]}';
";;
routines)
psql -tAd ${dbname} <<<"
SELECT name
FROM routine;
";;
sets)
# -tA is omitted as we're borrowing the
# formatting from the database and only
# want to turn off the row count footer
psql -P footer=off -d ${dbname} <<<"
SELECT weight, reps, date
FROM ${routine[$workingroutine]}
WHERE machine='${machine[${workingmachine}]}';
";;
setdates)
psql -P footer=off -d ${dbname} <<<"
SELECT DISTINCT date
FROM ${routine[$workingroutine]}
WHERE machine='${machine[${workingmachine}]}';
";;
datedsets)
psql -P footer=off -d ${dbname} <<<"
SELECT weight, reps
FROM ${routine[$workingroutine]}
WHERE machine='${machine[${workingmachine}]}'
AND date='${date}';
";;
esac
}
# writing
insert() {
local command="$1"; shift
case $command in
newset)
psql -qd ${dbname} <<<"
INSERT INTO ${routine[$workingroutine]}
(date, machine, weight, setno, reps)
VALUES
('${currentdate}',
'${machine[${workingmachine}]}',
'${weight}',
'${setnumber}',
'${reps}');
";;
newmachine)
psql -qd ${dbname} <<<"
INSERT INTO machine
(name, routine)
VALUES
('${newmachine}',
'${routine[${workingroutine}]}');
";;
newroutine)
psql -qd ${dbname} <<<"
BEGIN;
INSERT INTO routine
(name)
VALUES
('${newroutine}');
CREATE TABLE IF NOT EXISTS ${newroutine} (
date date NOT NULL,
machine text NOT NULL REFERENCES machine(name),
weight real NOT NULL,
setno smallint NOT NULL,
reps smallint NOT NULL
);
COMMIT;
"
echo $?
;;
esac
}
## data handling
# serialize queries
get() {
local command=$1; shift
case $command in
machines)
local i
local j
while read i; do
# this is 1 indexed to avoid math later on
(( j++ ))
machine[$j]="$i"
done < <( query machines )
;;
routines)
local i
local j
while read i; do
# this is 1 indexed to avoid math later on
(( j++ ))
routine[$j]="$i"
done < <( query routines )
;;
esac
}
# present serialized queries
numerate() {
local command=$1; shift
case $command in
machines)
local i
(( i++ ))
while [[ -n ${machine[$i]} ]]; do
echo "($i) ${machine[$i]@u}"
(( i++ ))
done
;;
routines)
local i
(( i++ ))
while [[ -n ${routine[$i]} ]]; do
echo "($i) ${routine[$i]@u}"
(( i++ ))
done
;;
esac
}
## user interface
# statuses
showpastselections() {
clear
if [ "${routine[$workingroutine]}" ]; then
echo "Routine: ${routine[$workingroutine]@u}"
fi
if [ "${machine[${workingmachine}]}" ]; then
echo "Machine: ${machine[${workingmachine}]@u}"
fi
if [ "${weight}" ]; then
echo "Weight: ${weight}Kg"
fi
if [ "${setnumber}" ]; then
echo "Set: ${setnumber}"
fi
}
# menus
onlydated?() {
showpastselections
echo "${onlydatedmenu}"
read -p "${selectprompt}" onlydated
case $onlydated in
1)
query sets
;;
2)
echo "${datemenu}"
query setdates
read -p "${dateselectprompt}" date
query datedsets
;;
esac
}
reps?() {
(( setnumber++ ))
showpastselections
read -p "${repsprompt}" reps
insert newset
echo "${repeatrepsmenu}"
read -p "${selectprompt}" repeat
if [ "${repeat}" = "y" ]; then
reps?
fi
}
weight?() {
showpastselections
read -p "${weightprompt}" weight
reps?
unset setnumber
echo "${repeatweightmenu}"
read -p "${selectprompt}" repeat
if [ "${repeat}" = "y" ]; then
unset weight
weight?
fi
}
vieworlog?() {
showpastselections
echo "${vieworlogmenu}"
read -p "${selectprompt}" mode
case $mode in
1) # view
onlydated?
;;
2) # log
weight?
;;
esac
echo "${repeatviewreadmenu}"
read -p "${selectprompt}" repeat
if [ "${repeat}" = "y" ]; then
vieworlog?
fi
}
machine?() {
showpastselections
declare -a machine
get machines
echo "${machinemenu}"
numerate machines
echo "(0) New machine"
read -p "${selectprompt}" workingmachine
newmachine?
if [ "${workingmachine}" ] &&
[ "${workingmachine}" != 0 ]; then
vieworlog?
fi
echo "${repeatmachinemenu}"
if [ "${workingmachine}" != 0 ]; then
read -p "${selectprompt}" repeat
if [ "${repeat}" = "y" ]; then
unset workingmachine
machine?
fi
else
machine?
fi
}
newmachine?(){
if [ "${workingmachine}" = '0' ]; then
read -p "${newmachineprompt}" newmachine
if [ "${newmachine}" ]; then
insert newmachine
fi
fi
}
newroutine?(){
if [ "${workingroutine}" = '0' ]; then
read -p "${newroutineprompt}" newroutine
if [ "${newroutine}" ]; then
insert newroutine
fi
fi
}
routines?() {
showpastselections
get routines
echo "${routinemenu}"
numerate routines
echo "(0) New routine"
read -p "${selectprompt}" workingroutine
newroutine?
if [ "${workingroutine}" ] &&
[ "${workingroutine}" != 0 ]; then
machine?
fi
if [ -z "${workingroutine}" ] ||
[ "${newroutine}" ]; then
routines?
fi
}
main() {
routines?
}
### function calls
main