eletrotupi / tcc/ commit / c941890

api: share one timeToCron helper across the reminder syncers

The daily and medicine reminder syncers each carried the same private
timeToCron, so the reminder pattern could drift between them. It now
lives once in calc.ts and both syncers import it, leaving the generated
cron strings and the repeat options unchanged.
Pedro Lucas Porcellis porcellis@eletrotupi.com · 10 days ago c941890054e469bdf624c967e653c5c48b4fb80f Browse files
Parents fe4f998
Changed files
4
Additions
+26
Deletions
-12
api/src/services/dailyReminder.sync.ts
1 1
import { User } from "@prisma/client";
2 2
import { getQueue } from "@app/lib/queue/QueueRegistry";
3 3
import { DailyReminderJobName } from "@app/lib/queue/types";
4 4
import { logger } from "@app/lib/logger";
5 -

6 -
// XXX: Might be moved to the utilities?
7 -
function timeToCron(time: string): string {
8 -
  const [hour, minute] = time.split(":").map(Number);
9 -
  return `${minute} ${hour} * * *`;
10 -
}
5 +
import { timeToCron } from "@app/utils/calc";
11 6

12 7
export async function syncDailyReminderJob(user: User): Promise<void> {
13 8
  logger.info({ userId: user.id }, "[daily-sync] syncing user");
14 9

15 10
  const queue = getQueue("daily-reminders");
44 39
  logger.info(
45 40
    { userId: user.id, time: user.dailyReminderTime, cron },
46 41
    "[daily-sync] scheduled daily reminder",
47 42
  );
48 43
}
api/src/services/medicineReminder.sync.ts
1 1
import { MedicineRegimen } from "@prisma/client";
2 2
import { getQueue } from "@app/lib/queue/QueueRegistry";
3 3
import { MedicineReminderJobName } from "@app/lib/queue/types";
4 4
import { logger } from "@app/lib/logger";
5 -

6 -
function timeToCron(time: string): string {
7 -
  const [hour, minute] = time.split(":").map(Number);
8 -
  return `${minute} ${hour} * * *`;
9 -
}
5 +
import { timeToCron } from "@app/utils/calc";
10 6

11 7
export async function syncMedicineReminderJobs(
12 8
  regimen: MedicineRegimen
13 9
): Promise<void> {
14 10
  logger.info(
76 72
      { regimenId: regimen.id, time, cron },
77 73
      "[medicine-sync] scheduled job",
78 74
    );
79 75
  }
80 76
}
api/src/utils/calc.ts
1 1
// TODO: Move other calculations here
2 2
export const avg = (values: number[]) =>
3 3
  values.reduce((a, b) => a + b, 0) / values.length;
4 4

5 5
export const formatHours = (hours: number): string => {
41 41
    page,
42 42
    skip,
43 43
    nextPage: page < totalPages ? page + 1 : null,
44 44
  };
45 45
}
46 +

47 +
export const timeToCron = (time: string): string => {
48 +
  const [hour, minute] = time.split(":").map(Number);
49 +
  return `${minute} ${hour} * * *`;
50 +
}
api/tests/utils/calc.unit.test.ts
1 1
import { describe, it, expect } from 'vitest'
2 -
import { avg, formatHours, formatDiff, paginate } from '@app/utils/calc'
2 +
import { avg, formatHours, formatDiff, paginate, timeToCron } from '@app/utils/calc'
3 3

4 4
describe('avg', () => {
5 5
  it('averages a list of numbers', () => {
6 6
    expect(avg([2, 4, 6])).toBe(4)
7 7
  })
74 74

75 75
  it('has no next page for an empty result set', () => {
76 76
    expect(paginate(1, 10, 0)).toEqual({ page: 1, skip: 0, nextPage: null })
77 77
  })
78 78
})
79 +

80 +
describe('timeToCron', () => {
81 +
  it('puts the minute before the hour', () => {
82 +
    expect(timeToCron('23:59')).toBe('59 23 * * *')
83 +
  })
84 +

85 +
  it('drops the leading zero from the hour', () => {
86 +
    expect(timeToCron('07:05')).toBe('5 7 * * *')
87 +
  })
88 +

89 +
  it('maps midnight to zero hour and minute', () => {
90 +
    expect(timeToCron('00:00')).toBe('0 0 * * *')
91 +
  })
92 +

93 +
  it('maps midday to the twelfth hour', () => {
94 +
    expect(timeToCron('12:00')).toBe('0 12 * * *')
95 +
  })
96 +
})