@nickchristensen/cliftin 1.3.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,7 +73,7 @@ DESCRIPTION
73
73
  List exercises
74
74
  ```
75
75
 
76
- _See code: [src/commands/exercises/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.1/src/commands/exercises/list.ts)_
76
+ _See code: [src/commands/exercises/list.ts](https://github.com/nickchristensen/cliftin/blob/v2.1.0/src/commands/exercises/list.ts)_
77
77
 
78
78
  ## `cliftin exercises show SELECTOR`
79
79
 
@@ -107,7 +107,7 @@ DESCRIPTION
107
107
  Show one exercise detail and history
108
108
  ```
109
109
 
110
- _See code: [src/commands/exercises/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.1/src/commands/exercises/show.ts)_
110
+ _See code: [src/commands/exercises/show.ts](https://github.com/nickchristensen/cliftin/blob/v2.1.0/src/commands/exercises/show.ts)_
111
111
 
112
112
  ## `cliftin help [COMMAND]`
113
113
 
@@ -144,7 +144,7 @@ DESCRIPTION
144
144
  List programs
145
145
  ```
146
146
 
147
- _See code: [src/commands/programs/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.1/src/commands/programs/list.ts)_
147
+ _See code: [src/commands/programs/list.ts](https://github.com/nickchristensen/cliftin/blob/v2.1.0/src/commands/programs/list.ts)_
148
148
 
149
149
  ## `cliftin programs show [SELECTOR]`
150
150
 
@@ -164,7 +164,7 @@ DESCRIPTION
164
164
  Show one program hierarchy
165
165
  ```
166
166
 
167
- _See code: [src/commands/programs/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.1/src/commands/programs/show.ts)_
167
+ _See code: [src/commands/programs/show.ts](https://github.com/nickchristensen/cliftin/blob/v2.1.0/src/commands/programs/show.ts)_
168
168
 
169
169
  ## `cliftin workouts list`
170
170
 
@@ -191,7 +191,7 @@ DESCRIPTION
191
191
  List workouts
192
192
  ```
193
193
 
194
- _See code: [src/commands/workouts/list.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.1/src/commands/workouts/list.ts)_
194
+ _See code: [src/commands/workouts/list.ts](https://github.com/nickchristensen/cliftin/blob/v2.1.0/src/commands/workouts/list.ts)_
195
195
 
196
196
  ## `cliftin workouts next`
197
197
 
@@ -208,7 +208,7 @@ DESCRIPTION
208
208
  Show the up-next routine from the active program
209
209
  ```
210
210
 
211
- _See code: [src/commands/workouts/next.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.1/src/commands/workouts/next.ts)_
211
+ _See code: [src/commands/workouts/next.ts](https://github.com/nickchristensen/cliftin/blob/v2.1.0/src/commands/workouts/next.ts)_
212
212
 
213
213
  ## `cliftin workouts show [WORKOUTID]`
214
214
 
@@ -228,5 +228,5 @@ DESCRIPTION
228
228
  Show one workout with exercises and sets
229
229
  ```
230
230
 
231
- _See code: [src/commands/workouts/show.ts](https://github.com/nickchristensen/cliftin/blob/v1.3.1/src/commands/workouts/show.ts)_
231
+ _See code: [src/commands/workouts/show.ts](https://github.com/nickchristensen/cliftin/blob/v2.1.0/src/commands/workouts/show.ts)_
232
232
  <!-- commandsstop -->
@@ -36,8 +36,12 @@ export default class Exercises extends Command {
36
36
  name: flags.name,
37
37
  sort: flags.sort,
38
38
  });
39
- if (this.jsonEnabled())
40
- return exercises;
39
+ if (this.jsonEnabled()) {
40
+ return exercises.map(({ id, ...exercise }) => ({
41
+ ...exercise,
42
+ exerciseId: id,
43
+ }));
44
+ }
41
45
  this.log(renderTable(exercises.map((exercise) => ({
42
46
  equipment: exercise.equipment,
43
47
  id: exercise.id,
@@ -64,20 +64,11 @@ export default class ExercisesShow extends Command {
64
64
  })),
65
65
  topWeight: withWeightUnit(row.topWeight, historyUnitPreference),
66
66
  }));
67
+ const { id: detailId, ...exerciseDetail } = detail;
67
68
  return {
68
- defaultProgressMetric: detail.defaultProgressMetric,
69
- equipment: detail.equipment,
69
+ exerciseId: detailId,
70
+ ...exerciseDetail,
70
71
  history,
71
- id: detail.id,
72
- name: detail.name,
73
- perceptionScale: detail.perceptionScale,
74
- primaryMuscles: detail.primaryMuscles,
75
- recentRoutines: detail.recentRoutines,
76
- secondaryMuscles: detail.secondaryMuscles,
77
- supports1RM: detail.supports1RM,
78
- timerBased: detail.timerBased,
79
- totalRoutines: detail.totalRoutines,
80
- totalWorkouts: detail.totalWorkouts,
81
72
  };
82
73
  }
83
74
  this.log(`[${detail.id}] ${detail.name ?? '(unnamed)'}`);
@@ -103,6 +94,7 @@ export default class ExercisesShow extends Command {
103
94
  this.log('');
104
95
  this.log(renderTable(lastPerformedSnapshot.exercise.sets.map((set) => ({
105
96
  id: set.id,
97
+ isWarmup: set.isWarmup,
106
98
  reps: set.reps,
107
99
  rpe: set.rpe,
108
100
  timeSeconds: set.timeSeconds,
@@ -10,8 +10,12 @@ export default class Programs extends Command {
10
10
  const context = openDb();
11
11
  try {
12
12
  const programs = await listPrograms(context.db);
13
- if (this.jsonEnabled())
14
- return programs;
13
+ if (this.jsonEnabled()) {
14
+ return programs.map(({ id, ...program }) => ({
15
+ ...program,
16
+ programId: id,
17
+ }));
18
+ }
15
19
  this.log(renderTable(programs.map((program) => ({
16
20
  dateAdded: program.dateAdded,
17
21
  id: program.id,
@@ -35,12 +35,13 @@ export default class Workouts extends Command {
35
35
  to: flags.to,
36
36
  });
37
37
  if (this.jsonEnabled()) {
38
- return workouts.map((workout) => ({
38
+ return workouts.map(({ duration, id, ...workout }) => ({
39
39
  ...workout,
40
40
  duration: {
41
41
  unit: 'seconds',
42
- value: workout.duration,
42
+ value: duration,
43
43
  },
44
+ workoutId: id,
44
45
  }));
45
46
  }
46
47
  this.log(renderTable(workouts.map((workout) => {
@@ -61,6 +61,7 @@ export default class WorkoutsShow extends Command {
61
61
  this.log(`[${exercise.exerciseId ?? exercise.exerciseResultId}] ${exercise.name ?? '(unnamed)'}`);
62
62
  this.log(renderTable(exercise.sets.map((set) => ({
63
63
  id: set.id,
64
+ isWarmup: set.isWarmup,
64
65
  reps: set.reps,
65
66
  rpe: set.rpe,
66
67
  timeSeconds: set.timeSeconds,
package/dist/lib/db.d.ts CHANGED
@@ -47,6 +47,7 @@ export interface DatabaseSchema {
47
47
  ZRPE: null | number;
48
48
  ZTIME: null | number;
49
49
  ZVOLUME: null | number;
50
+ ZWARMUPSET: null | number;
50
51
  ZWEIGHT: null | number;
51
52
  };
52
53
  ZPERIOD: {
@@ -1,4 +1,7 @@
1
1
  import { withWeightUnit } from './units.js';
2
+ function omitId(value) {
3
+ return Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'id'));
4
+ }
2
5
  export function serializeExerciseHistoryRowsWithWeightUnits(rows, unitPreference) {
3
6
  return rows.map((row) => ({
4
7
  ...row,
@@ -6,46 +9,62 @@ export function serializeExerciseHistoryRowsWithWeightUnits(rows, unitPreference
6
9
  }));
7
10
  }
8
11
  export function serializeProgramDetailWithWeightUnits(detail, unitPreference) {
12
+ const program = omitId(detail.program);
9
13
  return {
10
- ...detail,
14
+ program: { ...program, programId: detail.program.id },
11
15
  weeks: detail.weeks.map((week) => ({
12
- ...week,
13
16
  routines: week.routines.map((routine) => ({
14
- ...routine,
17
+ ...omitId(routine),
15
18
  exercises: routine.exercises.map((exercise) => ({
16
- ...exercise,
19
+ ...omitId(exercise),
20
+ exerciseId: exercise.id,
17
21
  plannedWeight: withWeightUnit(exercise.plannedWeight, unitPreference),
18
22
  sets: exercise.sets.map((set) => ({
19
- ...set,
23
+ ...omitId(set),
24
+ setId: set.id,
20
25
  weight: withWeightUnit(set.weight, unitPreference),
21
26
  })),
22
27
  })),
28
+ routineId: routine.id,
23
29
  })),
30
+ weekId: week.id,
24
31
  })),
25
32
  };
26
33
  }
27
34
  export function serializeNextWorkoutDetailWithWeightUnits(detail, unitPreference) {
35
+ const program = omitId(detail.program);
28
36
  return {
29
- ...detail,
37
+ program: { ...program, programId: detail.program.id },
30
38
  routine: {
31
- ...detail.routine,
39
+ ...omitId(detail.routine),
32
40
  exercises: detail.routine.exercises.map((exercise) => ({
33
- ...exercise,
41
+ ...omitId(exercise),
42
+ exerciseId: exercise.id,
34
43
  plannedWeight: withWeightUnit(exercise.plannedWeight, unitPreference),
35
44
  sets: exercise.sets.map((set) => ({
36
- ...set,
45
+ ...omitId(set),
46
+ setId: set.id,
37
47
  weight: withWeightUnit(set.weight, unitPreference),
38
48
  })),
39
49
  })),
50
+ routineId: detail.routine.id,
51
+ },
52
+ week: {
53
+ number: detail.week.number,
54
+ weekId: detail.week.id,
40
55
  },
41
56
  };
42
57
  }
43
58
  export function serializeWorkoutDetailWithWeightUnits(detail, unitPreference) {
44
59
  return {
45
- ...detail,
60
+ date: detail.date,
61
+ duration: detail.duration,
46
62
  exercises: detail.exercises.map((exercise) => ({
47
- ...exercise,
63
+ exerciseId: exercise.exerciseId,
64
+ exerciseResultId: exercise.exerciseResultId,
65
+ name: exercise.name,
48
66
  sets: exercise.sets.map((set) => ({
67
+ isWarmup: set.isWarmup,
49
68
  reps: set.reps,
50
69
  rpe: set.rpe,
51
70
  setId: set.id,
@@ -54,5 +73,8 @@ export function serializeWorkoutDetailWithWeightUnits(detail, unitPreference) {
54
73
  weight: withWeightUnit(set.weight, unitPreference),
55
74
  })),
56
75
  })),
76
+ program: detail.program,
77
+ routine: detail.routine,
78
+ workoutId: detail.id,
57
79
  };
58
80
  }
@@ -7,6 +7,11 @@ import { getWorkoutDetail } from './workouts.js';
7
7
  function asBool(value) {
8
8
  return value === 1;
9
9
  }
10
+ const workingSetCountExpr = sql `sum(case when gs.Z_PK is not null and coalesce(gs.ZWARMUPSET, 0) != 1 then 1 else 0 end)`;
11
+ const workingSetTotalRepsExpr = sql `coalesce(sum(case when coalesce(gs.ZWARMUPSET, 0) != 1 then gs.ZREPS else 0 end), 0)`;
12
+ const workingSetTopRepsExpr = sql `max(case when coalesce(gs.ZWARMUPSET, 0) != 1 then gs.ZREPS end)`;
13
+ const workingSetTopWeightExpr = sql `max(case when coalesce(gs.ZWARMUPSET, 0) != 1 then gs.ZWEIGHT end)`;
14
+ const workingSetVolumeExpr = sql `coalesce(sum(case when coalesce(gs.ZWARMUPSET, 0) != 1 then gs.ZVOLUME else 0 end), 0)`;
10
15
  function renderSelectorCandidateList(candidates) {
11
16
  return candidates
12
17
  .map((candidate) => ({
@@ -142,11 +147,11 @@ export async function getExerciseHistoryRows(db, exerciseId, filters) {
142
147
  'wr.ZSTARTDATE as startDate',
143
148
  'wr.ZROUTINENAME as routineNameFromResult',
144
149
  'r.ZNAME as routineNameFromPlan',
145
- (eb) => eb.fn.count('gs.Z_PK').as('sets'),
146
- (eb) => eb.fn.coalesce(eb.fn.sum('gs.ZREPS'), eb.val(0)).as('totalReps'),
147
- (eb) => eb.fn.max('gs.ZREPS').as('topReps'),
148
- (eb) => eb.fn.max('gs.ZWEIGHT').as('topWeight'),
149
- (eb) => eb.fn.coalesce(eb.fn.sum('gs.ZVOLUME'), eb.val(0)).as('volume'),
150
+ workingSetCountExpr.as('sets'),
151
+ workingSetTotalRepsExpr.as('totalReps'),
152
+ workingSetTopRepsExpr.as('topReps'),
153
+ workingSetTopWeightExpr.as('topWeight'),
154
+ workingSetVolumeExpr.as('volume'),
150
155
  ])
151
156
  .where('ei.Z_PK', '=', exerciseId)
152
157
  .groupBy(['wr.Z_PK', 'wr.ZSTARTDATE', 'wr.ZROUTINENAME', 'r.ZNAME'])
@@ -164,13 +169,13 @@ export async function getExerciseHistoryRows(db, exerciseId, filters) {
164
169
  if (dateRange.to !== undefined)
165
170
  query = query.where('wr.ZSTARTDATE', '<=', dateRange.to);
166
171
  if (filters.minReps !== undefined)
167
- query = query.having((eb) => eb.fn.max('gs.ZREPS'), '>=', filters.minReps);
172
+ query = query.having(workingSetTopRepsExpr, '>=', filters.minReps);
168
173
  if (filters.maxReps !== undefined)
169
- query = query.having((eb) => eb.fn.max('gs.ZREPS'), '<=', filters.maxReps);
174
+ query = query.having(workingSetTopRepsExpr, '<=', filters.maxReps);
170
175
  if (minWeightKg !== undefined)
171
- query = query.having((eb) => eb.fn.max('gs.ZWEIGHT'), '>=', minWeightKg);
176
+ query = query.having(workingSetTopWeightExpr, '>=', minWeightKg);
172
177
  if (maxWeightKg !== undefined)
173
- query = query.having((eb) => eb.fn.max('gs.ZWEIGHT'), '<=', maxWeightKg);
178
+ query = query.having(workingSetTopWeightExpr, '<=', maxWeightKg);
174
179
  if (filters.limit !== undefined)
175
180
  query = query.limit(filters.limit);
176
181
  const rows = await query.execute();
@@ -199,6 +204,7 @@ export async function getExerciseHistoryWithSetsRows(db, exerciseId, filters) {
199
204
  date: summary.date,
200
205
  routine: summary.routine,
201
206
  sets: (exercise?.sets ?? []).map((set) => ({
207
+ isWarmup: set.isWarmup,
202
208
  reps: set.reps,
203
209
  setId: set.id,
204
210
  timeSeconds: set.timeSeconds,
@@ -136,6 +136,7 @@ export async function getWorkoutDetail(db, workoutId) {
136
136
  'ZWEIGHT as weight',
137
137
  'ZTIME as timeSeconds',
138
138
  'ZVOLUME as volume',
139
+ 'ZWARMUPSET as warmupSet',
139
140
  ])
140
141
  .where('ZEXERCISE', 'in', exerciseResultIds)
141
142
  .orderBy('Z_FOK_EXERCISE', 'asc')
@@ -148,6 +149,7 @@ export async function getWorkoutDetail(db, workoutId) {
148
149
  const current = setsByExercise.get(row.exerciseResultId) ?? [];
149
150
  current.push({
150
151
  id: row.id,
152
+ isWarmup: asBool(row.warmupSet),
151
153
  reps: row.reps,
152
154
  rpe: normalizeRpe(row.rpe),
153
155
  timeSeconds: row.timeSeconds,
@@ -48,6 +48,7 @@ export type WorkoutSummary = {
48
48
  };
49
49
  export type WorkoutSet = {
50
50
  id: number;
51
+ isWarmup: boolean;
51
52
  reps: null | number;
52
53
  rpe: null | number;
53
54
  timeSeconds: null | number;
@@ -98,6 +99,7 @@ export type ExerciseHistoryRow = {
98
99
  workoutId: number;
99
100
  };
100
101
  export type ExerciseHistorySet = {
102
+ isWarmup: boolean;
101
103
  reps: null | number;
102
104
  setId: number;
103
105
  timeSeconds: null | number;
@@ -399,5 +399,5 @@
399
399
  ]
400
400
  }
401
401
  },
402
- "version": "1.3.1"
402
+ "version": "2.1.0"
403
403
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nickchristensen/cliftin",
3
3
  "description": "CLIftin: A read-only CLI for Liftin'",
4
- "version": "1.3.1",
4
+ "version": "2.1.0",
5
5
  "author": "Nick Christensen",
6
6
  "bin": {
7
7
  "cliftin": "./bin/run.js"