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 filesParents
fe4f998Changed 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 +
})