alpha
Login
or
Join now
dunkirk.sh
/
smokie
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
This repository has no description
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
feat: fix user total drift
author
Kieran Klukas
date
1 year ago
(May 29, 2025, 10:09 PM -0400)
commit
00bbd6ba
00bbd6ba73844b86e4bc6097d0b57b82bc45e62d
parent
1425e9b2
1425e9b212bd36129cb23b1f2ccb44f94c27c8f8
+110
2 changed files
Expand all
Collapse all
Unified
Split
src
features
takes
index.ts
libs
userTotals.ts
+22
src/features/takes/index.ts
Reviewed
···
1
1
import setupCommands from "./setup/commands";
2
2
import setupActions from "./setup/actions";
3
3
+
import { validateAndFixUserTotals } from "../../libs/userTotals";
4
4
+
import * as Sentry from "@sentry/bun";
3
5
4
6
const takes = async () => {
5
7
setupCommands();
6
8
setupActions();
9
9
+
10
10
+
// Validate and fix user totals on startup
11
11
+
try {
12
12
+
const result = await validateAndFixUserTotals();
13
13
+
if (result.fixed > 0) {
14
14
+
console.log(`Fixed ${result.fixed} users with total takes time drift`);
15
15
+
}
16
16
+
if (result.errors.length > 0) {
17
17
+
console.error(`Failed to fix ${result.errors.length} users`);
18
18
+
Sentry.captureMessage("Failed to fix some user totals", {
19
19
+
level: "warning",
20
20
+
extra: { errors: result.errors }
21
21
+
});
22
22
+
}
23
23
+
} catch (error) {
24
24
+
console.error("Error while validating user totals:", error);
25
25
+
Sentry.captureException(error, {
26
26
+
tags: { type: "user_totals_validation" }
27
27
+
});
28
28
+
}
7
29
};
8
30
9
31
export default takes;
+88
src/libs/userTotals.ts
Reviewed
···
1
1
+
import { db } from "./db";
2
2
+
import { users as usersTable, takes as takesTable } from "./schema";
3
3
+
import { sql, eq, and, ne } from "drizzle-orm";
4
4
+
5
5
+
/**
6
6
+
* Finds and corrects any drift between the computed user total time and the stored value.
7
7
+
* This helps ensure time calculations remain accurate even if triggers fail or data gets out of sync.
8
8
+
*/
9
9
+
export async function validateAndFixUserTotals() {
10
10
+
try {
11
11
+
console.log("Validating user totals...");
12
12
+
13
13
+
// First, get the calculated totals per user
14
14
+
const calculatedTotals = await db
15
15
+
.select({
16
16
+
userId: takesTable.userId,
17
17
+
calculatedTotal:
18
18
+
sql<number>`COALESCE(SUM(${takesTable.elapsedTime}), 0)::integer`.as(
19
19
+
"calculated_total",
20
20
+
),
21
21
+
})
22
22
+
.from(takesTable)
23
23
+
.groupBy(takesTable.userId);
24
24
+
25
25
+
// Convert to a map for easier lookup
26
26
+
const totalsMap = new Map(
27
27
+
calculatedTotals.map((item) => [item.userId, item.calculatedTotal]),
28
28
+
);
29
29
+
30
30
+
// Get all users
31
31
+
const allUsers = await db
32
32
+
.select({
33
33
+
id: usersTable.id,
34
34
+
storedTotal: usersTable.totalTakesTime,
35
35
+
})
36
36
+
.from(usersTable);
37
37
+
38
38
+
// Find users with drift
39
39
+
const driftedUsers = allUsers
40
40
+
.filter((user) => {
41
41
+
const calculatedTotal = totalsMap.get(user.id) || 0;
42
42
+
return user.storedTotal !== calculatedTotal;
43
43
+
})
44
44
+
.map((user) => ({
45
45
+
id: user.id,
46
46
+
storedTotal: user.storedTotal,
47
47
+
calculatedTotal: totalsMap.get(user.id) || 0,
48
48
+
}));
49
49
+
50
50
+
if (driftedUsers.length === 0) {
51
51
+
console.log("✅ All user totals are in sync");
52
52
+
return { fixed: 0, errors: [] };
53
53
+
}
54
54
+
55
55
+
console.log(
56
56
+
`❌ Found ${driftedUsers.length} users with incorrect totals`,
57
57
+
);
58
58
+
59
59
+
// Fix each drifted user
60
60
+
const errors: string[] = [];
61
61
+
let fixed = 0;
62
62
+
63
63
+
for (const user of driftedUsers) {
64
64
+
try {
65
65
+
await db
66
66
+
.update(usersTable)
67
67
+
.set({ totalTakesTime: user.calculatedTotal })
68
68
+
.where(eq(usersTable.id, user.id));
69
69
+
70
70
+
console.log(
71
71
+
`Fixed user ${user.id}: ${user.storedTotal} → ${user.calculatedTotal}`,
72
72
+
);
73
73
+
fixed++;
74
74
+
} catch (error) {
75
75
+
const errorMsg = `Failed to fix user ${user.id}: ${error}`;
76
76
+
console.error(errorMsg);
77
77
+
errors.push(errorMsg);
78
78
+
}
79
79
+
}
80
80
+
81
81
+
console.log(`✅ Fixed ${fixed} user totals`);
82
82
+
83
83
+
return { fixed, errors };
84
84
+
} catch (error) {
85
85
+
console.error("Error validating user totals:", error);
86
86
+
throw error;
87
87
+
}
88
88
+
}