Skip to content

Commit ab5ae7e

Browse files
committed
remove last lodash usage
1 parent a505578 commit ab5ae7e

File tree

10 files changed

+247
-243
lines changed

10 files changed

+247
-243
lines changed

backend/__tests__/__integration__/dal/user.spec.ts

Lines changed: 92 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -624,97 +624,129 @@ describe("UserDal", () => {
624624
});
625625
});
626626

627-
it("updateProfile should appropriately handle multiple profile updates", async () => {
628-
const uid = new ObjectId().toHexString();
629-
await UserDAL.addUser("test name", "test email", uid);
627+
describe("updateProfile", () => {
628+
it("updateProfile should appropriately handle multiple profile updates", async () => {
629+
const uid = new ObjectId().toHexString();
630+
await UserDAL.addUser("test name", "test email", uid);
630631

631-
await UserDAL.updateProfile(
632-
uid,
633-
{
632+
await UserDAL.updateProfile(
633+
uid,
634+
{
635+
bio: "test bio",
636+
},
637+
{
638+
badges: [],
639+
}
640+
);
641+
642+
const user = await UserDAL.getUser(uid, "test add result filters");
643+
expect(user.profileDetails).toStrictEqual({
634644
bio: "test bio",
635-
},
636-
{
645+
});
646+
expect(user.inventory).toStrictEqual({
637647
badges: [],
638-
}
639-
);
648+
});
640649

641-
const user = await UserDAL.getUser(uid, "test add result filters");
642-
expect(user.profileDetails).toStrictEqual({
643-
bio: "test bio",
644-
});
645-
expect(user.inventory).toStrictEqual({
646-
badges: [],
647-
});
650+
await UserDAL.updateProfile(
651+
uid,
652+
{
653+
keyboard: "test keyboard",
654+
socialProfiles: {
655+
twitter: "test twitter",
656+
},
657+
},
658+
{
659+
badges: [
660+
{
661+
id: 1,
662+
selected: true,
663+
},
664+
],
665+
}
666+
);
648667

649-
await UserDAL.updateProfile(
650-
uid,
651-
{
668+
const updatedUser = await UserDAL.getUser(uid, "test add result filters");
669+
expect(updatedUser.profileDetails).toStrictEqual({
670+
bio: "test bio",
652671
keyboard: "test keyboard",
653672
socialProfiles: {
654673
twitter: "test twitter",
655674
},
656-
},
657-
{
675+
});
676+
expect(updatedUser.inventory).toStrictEqual({
658677
badges: [
659678
{
660679
id: 1,
661680
selected: true,
662681
},
663682
],
664-
}
665-
);
683+
});
666684

667-
const updatedUser = await UserDAL.getUser(uid, "test add result filters");
668-
expect(updatedUser.profileDetails).toStrictEqual({
669-
bio: "test bio",
670-
keyboard: "test keyboard",
671-
socialProfiles: {
672-
twitter: "test twitter",
673-
},
674-
});
675-
expect(updatedUser.inventory).toStrictEqual({
676-
badges: [
685+
await UserDAL.updateProfile(
686+
uid,
677687
{
678-
id: 1,
679-
selected: true,
688+
bio: "test bio 2",
689+
socialProfiles: {
690+
github: "test github",
691+
website: "test website",
692+
},
680693
},
681-
],
682-
});
694+
{
695+
badges: [
696+
{
697+
id: 1,
698+
},
699+
],
700+
}
701+
);
683702

684-
await UserDAL.updateProfile(
685-
uid,
686-
{
703+
const updatedUser2 = await UserDAL.getUser(
704+
uid,
705+
"test add result filters"
706+
);
707+
expect(updatedUser2.profileDetails).toStrictEqual({
687708
bio: "test bio 2",
709+
keyboard: "test keyboard",
688710
socialProfiles: {
711+
twitter: "test twitter",
689712
github: "test github",
690713
website: "test website",
691714
},
692-
},
693-
{
715+
});
716+
expect(updatedUser2.inventory).toStrictEqual({
694717
badges: [
695718
{
696719
id: 1,
697720
},
698721
],
699-
}
700-
);
701-
702-
const updatedUser2 = await UserDAL.getUser(uid, "test add result filters");
703-
expect(updatedUser2.profileDetails).toStrictEqual({
704-
bio: "test bio 2",
705-
keyboard: "test keyboard",
706-
socialProfiles: {
707-
twitter: "test twitter",
708-
github: "test github",
709-
website: "test website",
710-
},
722+
});
711723
});
712-
expect(updatedUser2.inventory).toStrictEqual({
713-
badges: [
714-
{
715-
id: 1,
724+
it("should omit undefined or empty object values", async () => {
725+
//GIVEN
726+
const givenUser = await UserTestData.createUser({
727+
profileDetails: {
728+
bio: "test bio",
729+
keyboard: "test keyboard",
730+
socialProfiles: {
731+
twitter: "test twitter",
732+
github: "test github",
733+
},
716734
},
717-
],
735+
});
736+
737+
//WHEN
738+
await UserDAL.updateProfile(givenUser.uid, {
739+
bio: undefined, //ignored
740+
keyboard: "updates",
741+
socialProfiles: {}, //ignored
742+
});
743+
744+
//THEN
745+
const read = await UserDAL.getUser(givenUser.uid, "read");
746+
expect(read.profileDetails).toStrictEqual({
747+
...givenUser.profileDetails,
748+
keyboard: "updates",
749+
});
718750
});
719751
});
720752

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { describe, it, expect } from "vitest";
2+
import * as Configurations from "../../src/init/configuration";
3+
4+
import { Configuration } from "@monkeytype/schemas/configuration";
5+
const mergeConfigurations = Configurations.__testing.mergeConfigurations;
6+
7+
describe("configurations", () => {
8+
describe("mergeConfigurations", () => {
9+
it("should merge configurations correctly", () => {
10+
//GIVEN
11+
const baseConfig: Configuration = {
12+
maintenance: false,
13+
dev: {
14+
responseSlowdownMs: 5,
15+
},
16+
quotes: {
17+
reporting: {
18+
enabled: false,
19+
maxReports: 5,
20+
},
21+
submissionEnabled: true,
22+
},
23+
} as any;
24+
const liveConfig: Partial<Configuration> = {
25+
maintenance: true,
26+
quotes: {
27+
reporting: {
28+
enabled: true,
29+
} as any,
30+
maxFavorites: 10,
31+
} as any,
32+
};
33+
34+
//WHEN
35+
mergeConfigurations(baseConfig, liveConfig);
36+
37+
//THEN
38+
expect(baseConfig).toEqual({
39+
maintenance: true,
40+
dev: {
41+
responseSlowdownMs: 5,
42+
},
43+
quotes: {
44+
reporting: {
45+
enabled: true,
46+
maxReports: 5,
47+
},
48+
submissionEnabled: true,
49+
},
50+
} as any);
51+
});
52+
});
53+
});

backend/__tests__/setup-tests.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
import { afterAll, beforeAll, afterEach, vi } from "vitest";
22
import { BASE_CONFIGURATION } from "../src/constants/base-configuration";
33
import { setupCommonMocks } from "./setup-common-mocks";
4+
import { __testing } from "../src/init/configuration";
45

56
process.env["MODE"] = "dev";
67
process.env.TZ = "UTC";
78
beforeAll(async () => {
89
//don't add any configuration here, add to global-setup.ts instead.
910

10-
vi.mock("../src/init/configuration", () => ({
11-
getLiveConfiguration: () => BASE_CONFIGURATION,
12-
getCachedConfiguration: () => BASE_CONFIGURATION,
13-
patchConfiguration: vi.fn(),
14-
}));
11+
vi.mock("../src/init/configuration", async (importOriginal) => {
12+
const orig = (await importOriginal()) as { __testing: typeof __testing };
13+
14+
return {
15+
__testing: orig.__testing,
16+
getLiveConfiguration: () => BASE_CONFIGURATION,
17+
getCachedConfiguration: () => BASE_CONFIGURATION,
18+
patchConfiguration: vi.fn(),
19+
};
20+
});
1521

1622
vi.mock("../src/init/db", () => ({
1723
__esModule: true,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { describe, it, expect } from "vitest";
2+
import * as LaterWorker from "../../src/workers/later-worker";
3+
const calculateXpReward = LaterWorker.__testing.calculateXpReward;
4+
5+
describe("later-worker", () => {
6+
describe("calculateXpReward", () => {
7+
it("should return the correct XP reward for a given rank", () => {
8+
//GIVEN
9+
const xpRewardBrackets = [
10+
{ minRank: 1, maxRank: 1, minReward: 100, maxReward: 100 },
11+
{ minRank: 2, maxRank: 10, minReward: 50, maxReward: 90 },
12+
];
13+
14+
//WHEN / THEN
15+
expect(calculateXpReward(xpRewardBrackets, 5)).toBe(75);
16+
expect(calculateXpReward(xpRewardBrackets, 11)).toBeUndefined();
17+
});
18+
19+
it("should return the highest XP reward if brackets overlap", () => {
20+
//GIVEN
21+
const xpRewardBrackets = [
22+
{ minRank: 1, maxRank: 5, minReward: 900, maxReward: 1000 },
23+
{ minRank: 2, maxRank: 20, minReward: 50, maxReward: 90 },
24+
];
25+
26+
//WHEN
27+
const reward = calculateXpReward(xpRewardBrackets, 5);
28+
29+
//THEN
30+
expect(reward).toBe(900);
31+
});
32+
});
33+
});

backend/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@
3838
"cron": "2.3.0",
3939
"date-fns": "3.6.0",
4040
"dotenv": "16.4.5",
41+
"es-toolkit": "1.39.10",
4142
"etag": "1.8.1",
4243
"express": "5.1.0",
4344
"express-rate-limit": "7.5.1",
4445
"firebase-admin": "12.0.0",
4546
"helmet": "4.6.0",
4647
"ioredis": "4.28.5",
47-
"lodash": "4.17.21",
4848
"lru-cache": "7.10.1",
4949
"mjml": "4.15.0",
5050
"mongodb": "6.3.0",
@@ -72,7 +72,6 @@
7272
"@types/cron": "1.7.3",
7373
"@types/express": "5.0.3",
7474
"@types/ioredis": "4.28.10",
75-
"@types/lodash": "4.14.178",
7675
"@types/mjml": "4.7.4",
7776
"@types/mustache": "4.2.2",
7877
"@types/node": "20.14.11",

backend/src/dal/result.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,11 @@ export async function getResults(
113113
const { onOrAfterTimestamp, offset, limit } = opts ?? {};
114114

115115
const condition: Filter<DBResult> = { uid };
116-
if (onOrAfterTimestamp !== undefined && !isNaN(onOrAfterTimestamp)) {
116+
if (
117+
onOrAfterTimestamp !== undefined &&
118+
onOrAfterTimestamp !== null &&
119+
!isNaN(onOrAfterTimestamp)
120+
) {
117121
condition.timestamp = { $gte: onOrAfterTimestamp };
118122
}
119123

backend/src/dal/user.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import _ from "lodash";
21
import { canFunboxGetPb, checkAndUpdatePb, LbPersonalBests } from "../utils/pb";
32
import * as db from "../init/db";
43
import MonkeyError from "../utils/error";
@@ -905,9 +904,15 @@ export async function updateProfile(
905904
profileDetailUpdates: Partial<UserProfileDetails>,
906905
inventory?: UserInventory
907906
): Promise<void> {
908-
const profileUpdates = _.omitBy(
909-
flattenObjectDeep(profileDetailUpdates, "profileDetails"),
910-
(value) => value === undefined || (isPlainObject(value) && _.isEmpty(value))
907+
let profileUpdates = flattenObjectDeep(
908+
Object.fromEntries(
909+
Object.entries(profileDetailUpdates).filter(
910+
([_, value]) =>
911+
value !== undefined &&
912+
!(isPlainObject(value) && Object.keys(value).length === 0)
913+
)
914+
),
915+
"profileDetails"
911916
);
912917

913918
const updates = {

backend/src/init/configuration.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import _ from "lodash";
21
import * as db from "./db";
32
import { ObjectId } from "mongodb";
43
import Logger from "../utils/logger";
@@ -31,7 +30,10 @@ function mergeConfigurations(
3130
}
3231

3332
function merge(base: object, source: object): void {
34-
const commonKeys = _.intersection(_.keys(base), _.keys(source));
33+
const baseKeys = Object.keys(base);
34+
const sourceKeys = Object.keys(source);
35+
const commonKeys = baseKeys.filter((key) => sourceKeys.includes(key));
36+
3537
commonKeys.forEach((key) => {
3638
const baseValue = base[key] as object;
3739
const sourceValue = source[key] as object;
@@ -162,3 +164,7 @@ export async function updateFromConfigurationFile(): Promise<void> {
162164
await patchConfiguration(data.configuration);
163165
}
164166
}
167+
168+
export const __testing = {
169+
mergeConfigurations,
170+
};

backend/src/workers/later-worker.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,7 @@ export default (redisConnection?: IORedis.Redis): Worker => {
216216
});
217217
return worker;
218218
};
219+
220+
export const __testing = {
221+
calculateXpReward,
222+
};

0 commit comments

Comments
 (0)