Skip to content

Commit 01dbf16

Browse files
Fix validation bug when converting Someday events to Grid/Calendar events (#1003)
* Initial plan * Fix validation bug when converting Someday events to Grid events Co-authored-by: victor-enogwe <23452630+victor-enogwe@users.noreply.github.com> * 🐛 fix(event-conversion): someday to grid event fix * 🐛 fix(event-conversion): fix tests - remove mongo import from core pkg --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: victor-enogwe <23452630+victor-enogwe@users.noreply.github.com>
1 parent 37816a3 commit 01dbf16

File tree

12 files changed

+147
-91
lines changed

12 files changed

+147
-91
lines changed

packages/core/src/__mocks__/v1/events/events.22mar.ts

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { ObjectId, WithId } from "mongodb";
2-
import { Priorities } from "../../../constants/core.constants";
3-
import { Schema_Event } from "../../../types/event.types";
1+
import { ObjectId } from "bson";
2+
import { Priorities } from "@core/constants/core.constants";
3+
import { Schema_Event, WithMongoId } from "@core/types/event.types";
44

5-
const allDayEventsThatShouldMatch: Array<WithId<Omit<Schema_Event, "_id">>> =
5+
const allDayEventsThatShouldMatch: Array<
6+
WithMongoId<Omit<Schema_Event, "_id">>
7+
> =
68
// ordered by start date
79
[
810
{
@@ -43,49 +45,50 @@ const allDayEventsThatShouldMatch: Array<WithId<Omit<Schema_Event, "_id">>> =
4345
},
4446
];
4547

46-
const allDayEventsThatShouldNotMatch: Array<WithId<Omit<Schema_Event, "_id">>> =
47-
[
48-
{
49-
_id: new ObjectId(),
50-
user: "user1",
51-
title: "Feb 28 - Mar 5",
52-
isAllDay: true,
53-
isSomeday: false,
54-
startDate: "2022-02-28",
55-
endDate: "2022-03-05",
56-
priority: Priorities.WORK,
57-
},
58-
{
59-
_id: new ObjectId(),
60-
user: "user1",
61-
title: "Mar 5",
62-
isAllDay: true,
63-
isSomeday: false,
64-
startDate: "2022-03-05",
65-
endDate: "2022-03-06",
66-
priority: Priorities.WORK,
67-
},
68-
{
69-
_id: new ObjectId(),
70-
user: "user1",
71-
title: "Mar 13",
72-
isAllDay: true,
73-
isSomeday: false,
74-
startDate: "2022-03-13",
75-
endDate: "2022-03-14",
76-
priority: Priorities.WORK,
77-
},
78-
{
79-
_id: new ObjectId(),
80-
user: "user1",
81-
title: "Mar 13 - 16",
82-
isAllDay: true,
83-
isSomeday: false,
84-
startDate: "2022-03-13",
85-
endDate: "2022-03-17",
86-
priority: Priorities.WORK,
87-
},
88-
];
48+
const allDayEventsThatShouldNotMatch: Array<
49+
WithMongoId<Omit<Schema_Event, "_id">>
50+
> = [
51+
{
52+
_id: new ObjectId(),
53+
user: "user1",
54+
title: "Feb 28 - Mar 5",
55+
isAllDay: true,
56+
isSomeday: false,
57+
startDate: "2022-02-28",
58+
endDate: "2022-03-05",
59+
priority: Priorities.WORK,
60+
},
61+
{
62+
_id: new ObjectId(),
63+
user: "user1",
64+
title: "Mar 5",
65+
isAllDay: true,
66+
isSomeday: false,
67+
startDate: "2022-03-05",
68+
endDate: "2022-03-06",
69+
priority: Priorities.WORK,
70+
},
71+
{
72+
_id: new ObjectId(),
73+
user: "user1",
74+
title: "Mar 13",
75+
isAllDay: true,
76+
isSomeday: false,
77+
startDate: "2022-03-13",
78+
endDate: "2022-03-14",
79+
priority: Priorities.WORK,
80+
},
81+
{
82+
_id: new ObjectId(),
83+
user: "user1",
84+
title: "Mar 13 - 16",
85+
isAllDay: true,
86+
isSomeday: false,
87+
startDate: "2022-03-13",
88+
endDate: "2022-03-17",
89+
priority: Priorities.WORK,
90+
},
91+
];
8992

9093
export const mockEventSetMar22: Array<Omit<Schema_Event, "_id">> = [
9194
...allDayEventsThatShouldMatch,

packages/core/src/mappers/map.event.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-namespace */
22
import mergeWith from "lodash.mergewith";
3-
import { WithId } from "mongodb";
43
import { Origin, Priorities } from "@core/constants/core.constants";
54
import { BaseError } from "@core/errors/errors.base";
65
import {
@@ -11,6 +10,7 @@ import {
1110
Schema_Event_Recur_Instance,
1211
Schema_Event_Regular,
1312
WithCompassId,
13+
WithMongoId,
1414
WithoutCompassId,
1515
} from "@core/types/event.types";
1616
import { WithGcalId, gSchema$Event } from "@core/types/gcal";
@@ -37,9 +37,9 @@ export namespace MapEvent {
3737
};
3838

3939
export const removeProviderData = (
40-
event: WithId<Omit<Schema_Event, "_id">> | Schema_Event,
40+
event: WithMongoId<Omit<Schema_Event, "_id">> | Schema_Event,
4141
): Omit<
42-
WithId<Omit<Schema_Event, "_id">> | Schema_Event,
42+
WithMongoId<Omit<Schema_Event, "_id">> | Schema_Event,
4343
"gEventId" | "gRecurringEventId"
4444
> => {
4545
const {
@@ -57,7 +57,7 @@ export namespace MapEvent {
5757
};
5858

5959
export const removeIdentifyingData = (
60-
event: WithId<Omit<Schema_Event, "_id">> | Schema_Event,
60+
event: WithMongoId<Omit<Schema_Event, "_id">> | Schema_Event,
6161
): Omit<
6262
Schema_Event,
6363
| "_id"
@@ -128,7 +128,7 @@ export namespace MapEvent {
128128

129129
export const toGcalSingleProviderData = (
130130
base:
131-
| WithId<Omit<Schema_Event_Recur_Base | Schema_Event_Regular, "_id">>
131+
| WithMongoId<Omit<Schema_Event_Recur_Base | Schema_Event_Regular, "_id">>
132132
| WithCompassId<
133133
Omit<Schema_Event_Recur_Base | Schema_Event_Regular, "_id">
134134
>,
@@ -140,11 +140,11 @@ export namespace MapEvent {
140140

141141
export const toProviderData = (
142142
event:
143-
| WithId<Omit<Schema_Event, "_id" | "recurrence">>
143+
| WithMongoId<Omit<Schema_Event, "_id" | "recurrence">>
144144
| WithCompassId<Omit<Schema_Event, "_id" | "recurrence">>,
145145
provider?: CalendarProvider,
146146
base?:
147-
| WithId<Omit<Schema_Event_Recur_Base, "_id">>
147+
| WithMongoId<Omit<Schema_Event_Recur_Base, "_id">>
148148
| WithCompassId<Omit<Schema_Event_Recur_Base, "_id">>,
149149
) => {
150150
const isCInstance = isInstance(event);
@@ -153,7 +153,7 @@ export namespace MapEvent {
153153
case CalendarProvider.GOOGLE: {
154154
return isCInstance
155155
? MapEvent.toGcalInstanceProviderData(
156-
event as WithId<Omit<Schema_Event_Recur_Instance, "_id">>,
156+
event as WithMongoId<Omit<Schema_Event_Recur_Instance, "_id">>,
157157
base,
158158
)
159159
: MapEvent.toGcalSingleProviderData(event);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import { ObjectId } from "mongodb";
1+
import { ObjectId } from "bson";
22

33
export type InsertedIds = { [key: number]: ObjectId };

packages/core/src/types/sync.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AnyBulkWriteOperation, BulkWriteResult } from "mongodb";
1+
import type { AnyBulkWriteOperation, BulkWriteResult } from "mongodb";
22
import { BaseError } from "@core/errors/errors.base";
33

44
export interface Params_Sync_Gcal extends Payload_Sync_Notif {

packages/core/src/util/event/compass.event.rrule.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ObjectId, type WithId } from "mongodb";
1+
import { ObjectId } from "bson";
22
import { RRule } from "rrule";
33
import { faker } from "@faker-js/faker";
44
import { recurring } from "@core/__mocks__/v1/events/gcal/gcal.recurring";
@@ -7,6 +7,7 @@ import { gEventToCompassEvent } from "@core/mappers/map.event";
77
import {
88
CalendarProvider,
99
type Schema_Event_Recur_Base,
10+
WithMongoId,
1011
} from "@core/types/event.types";
1112
import dayjs from "@core/util/date/dayjs";
1213
import { CompassEventRRule } from "@core/util/event/compass.event.rrule";
@@ -390,7 +391,7 @@ describe("CompassEventRRule: ", () => {
390391
return event;
391392
});
392393

393-
const baseEvent = compassEvents.find(isBase) as WithId<
394+
const baseEvent = compassEvents.find(isBase) as WithMongoId<
394395
Omit<Schema_Event_Recur_Base, "_id">
395396
>;
396397

packages/core/src/util/event/compass.event.rrule.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { ObjectId } from "bson";
2-
import type { WithId } from "mongodb";
32
import type { Options, RRuleStrOptions } from "rrule";
43
import { RRule, rrulestr } from "rrule";
54
import type { ParsedOptions } from "rrule/dist/esm/types";
@@ -9,6 +8,7 @@ import type {
98
CalendarProvider,
109
Schema_Event_Recur_Base,
1110
Schema_Event_Recur_Instance,
11+
WithMongoId,
1212
} from "@core/types/event.types";
1313
import dayjs from "@core/util/date/dayjs";
1414
import {
@@ -18,13 +18,13 @@ import {
1818
} from "@core/util/event/event.util";
1919

2020
export class CompassEventRRule extends RRule {
21-
#event: WithId<Omit<Schema_Event_Recur_Base, "_id">>;
21+
#event: WithMongoId<Omit<Schema_Event_Recur_Base, "_id">>;
2222
#dateFormat: string;
2323
#durationMs!: number;
2424

2525
constructor(
2626
event: Pick<
27-
WithId<Omit<Schema_Event_Recur_Base, "_id">>,
27+
WithMongoId<Omit<Schema_Event_Recur_Base, "_id">>,
2828
"startDate" | "endDate" | "_id" | "recurrence"
2929
>,
3030
options: Partial<Options> = {},
@@ -41,7 +41,7 @@ export class CompassEventRRule extends RRule {
4141
}
4242

4343
static #initOptions(
44-
event: WithId<Omit<Schema_Event_Recur_Base, "_id">>,
44+
event: WithMongoId<Omit<Schema_Event_Recur_Base, "_id">>,
4545
_options: Partial<Options> = {},
4646
): Partial<Options> {
4747
const startDate = parseCompassEventDate(event.startDate!);
@@ -111,7 +111,7 @@ export class CompassEventRRule extends RRule {
111111

112112
base(
113113
provider?: CalendarProvider,
114-
): WithId<Omit<Schema_Event_Recur_Base, "_id">> {
114+
): WithMongoId<Omit<Schema_Event_Recur_Base, "_id">> {
115115
const _id = this.#event._id ?? new ObjectId();
116116
const recurrence = { rule: this.toRecurrence() };
117117
const event = { ...this.#event, _id, recurrence };
@@ -129,7 +129,7 @@ export class CompassEventRRule extends RRule {
129129
*/
130130
instances(
131131
provider?: CalendarProvider,
132-
): WithId<Omit<Schema_Event_Recur_Instance, "_id">>[] {
132+
): WithMongoId<Omit<Schema_Event_Recur_Instance, "_id">>[] {
133133
const base = this.base();
134134
const baseData = MapEvent.removeIdentifyingData(base);
135135
const baseEventId = base._id.toString();

packages/core/src/util/test/ccal.event.factory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ObjectId } from "mongodb";
1+
import { ObjectId } from "bson";
22
import { faker } from "@faker-js/faker";
33
import { Origin, Priorities } from "@core/constants/core.constants";
44
import {
@@ -8,7 +8,7 @@ import {
88
WithCompassId,
99
} from "@core/types/event.types";
1010
import dayjs from "@core/util/date/dayjs";
11-
import { isAllDay, parseCompassEventDate } from "../event/event.util";
11+
import { isAllDay, parseCompassEventDate } from "@core/util/event/event.util";
1212

1313
export const createMockStandaloneEvent = (
1414
overrides: Partial<Schema_Event> = {},

packages/web/src/common/types/web.event.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const WebEventRecurrence = z.union([
2424
]);
2525

2626
const WebCoreEventSchema = CompassCoreEventSchema.extend({
27-
_id: z.union([idSchema, optimisticIdSchema]),
27+
_id: z.union([idSchema, optimisticIdSchema]).optional(),
2828
recurrence: WebEventRecurrence,
2929
order: z.number().optional(),
3030
});

packages/web/src/common/utils/event.util.test.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { isEventInRange } from "./event.util";
1+
import { createMockStandaloneEvent } from "@core/util/test/ccal.event.factory";
2+
import {
3+
Schema_GridEvent,
4+
Schema_WebEvent,
5+
} from "@web/common/types/web.event.types";
6+
import { isEventInRange } from "@web/common/utils/event.util";
7+
import { _assembleGridEvent } from "@web/ducks/events/sagas/saga.util";
28

39
describe("isEventInRange", () => {
410
it("returns true if event is in range", () => {
@@ -9,6 +15,7 @@ describe("isEventInRange", () => {
915
};
1016
expect(isEventInRange(event, dates)).toBe(true);
1117
});
18+
1219
it("returns false if event is not in range", () => {
1320
const event = { start: "2022-03-15", end: "2022-03-15" };
1421
const dates = {
@@ -18,3 +25,31 @@ describe("isEventInRange", () => {
1825
expect(isEventInRange(event, dates)).toBe(false);
1926
});
2027
});
28+
29+
describe("_assembleGridEvent", () => {
30+
it("should successfully convert Someday event to Grid event by adding position field", () => {
31+
// Create a mock Someday event (without position field)
32+
const somedayEvent = createMockStandaloneEvent({
33+
isSomeday: true,
34+
}) as Schema_WebEvent;
35+
36+
const generator = _assembleGridEvent(somedayEvent);
37+
38+
// First, it calls getEventById
39+
const getEventStep = generator.next();
40+
expect(getEventStep.done).toBe(false);
41+
42+
// Mock returning the Someday event
43+
const validateStep = generator.next({ ...somedayEvent, isSomeday: false });
44+
45+
// This should now succeed because the fix adds the required position field
46+
expect(validateStep.done).toBe(true);
47+
const result = validateStep.value as Schema_GridEvent;
48+
49+
// Verify that position field is now present
50+
expect(result.position).toBeDefined();
51+
expect(result.position.isOverlapping).toBe(false);
52+
expect(result.position.widthMultiplier).toBe(1);
53+
expect(result.position.horizontalOrder).toBe(1);
54+
});
55+
});

packages/web/src/common/utils/event.util.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ import {
2121
Schema_OptimisticEvent,
2222
Schema_WebEvent,
2323
} from "@web/common/types/web.event.types";
24+
import { validateGridEvent } from "@web/common/validators/grid.event.validator";
2425
import { validateSomedayEvent } from "@web/common/validators/someday.event.validator";
25-
import { validateGridEvent } from "../validators/grid.event.validator";
2626

27-
const gridEventDefaultPosition = {
27+
export const gridEventDefaultPosition = {
2828
isOverlapping: false,
2929
widthMultiplier: 1,
3030
horizontalOrder: 1,
@@ -87,7 +87,7 @@ export const assembleDefaultEvent = async (
8787
}
8888
};
8989

90-
export const assembleGridEvent = (event: Schema_Event): Schema_GridEvent => {
90+
export const assembleGridEvent = (event: Schema_WebEvent): Schema_GridEvent => {
9191
const gridEvent: Schema_GridEvent = {
9292
...event,
9393
position: gridEventDefaultPosition,
@@ -97,7 +97,7 @@ export const assembleGridEvent = (event: Schema_Event): Schema_GridEvent => {
9797
origin: event.origin ?? Origin.COMPASS,
9898
priority: event.priority ?? Priorities.UNASSIGNED,
9999
user: event.user!,
100-
recurrence: event.recurrence as Schema_Event_Recur_Base["recurrence"],
100+
recurrence: event.recurrence,
101101
};
102102

103103
return gridEvent;
@@ -203,13 +203,10 @@ export const prepEvtAfterDraftDrop = (
203203
return event;
204204
};
205205

206-
export const prepEvtBeforeSubmit = (
207-
draft: Schema_Event | Schema_GridEvent,
208-
userId: string,
209-
) => {
210-
const _event: Omit<Schema_Event | Schema_GridEvent, "recurrence"> = {
206+
export const prepEvtBeforeSubmit = (draft: Schema_WebEvent, userId: string) => {
207+
const _event = {
211208
...draft,
212-
origin: Origin.COMPASS,
209+
origin: draft.origin ?? Origin.COMPASS,
213210
user: userId,
214211
};
215212

0 commit comments

Comments
 (0)