Skip to content

Commit

Permalink
feat: convert zod schema to camel case so parsing works
Browse files Browse the repository at this point in the history
  • Loading branch information
kimon-satan committed Dec 9, 2024
1 parent 21b3489 commit 5653d18
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 16 deletions.
51 changes: 51 additions & 0 deletions src/node-lib/curriculum-api-2023/helpers/zodToCamelCase.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { z } from "zod";

import { zodToCamelCase } from "./zodToCamelCase";

import keysToCamelCase from "@/utils/snakeCaseConverter";

describe("zodToCamelCase", () => {
it("converts a snake_case schema to camelCase", () => {
const snake_case_schema = z.object({
test_param: z.string(),
test_param2: z.number(),
});

const snake_data = {
test_param: "test",
test_param2: 123,
};

expect(snake_case_schema.parse(snake_data)).toEqual(snake_data);

const camelData = keysToCamelCase(snake_data);

const camelCaseSchema = zodToCamelCase(snake_case_schema);

expect(camelCaseSchema.parse(camelData)).toEqual(camelData);
});

it("converts a nested snake_case schema to camelCase", () => {
const nested_schema = z.object({
test_param: z.string(),
nested_param: z.object({
nested_param_2: z.number(),
}),
});

const nested_data = {
test_param: "test",
nested_param: {
nested_param_2: 123,
},
};

expect(nested_schema.parse(nested_data)).toEqual(nested_data);

const camelData = keysToCamelCase(nested_data);

const camelCaseSchema = zodToCamelCase(nested_schema);

expect(camelCaseSchema.parse(camelData)).toEqual(camelData);
});
});
24 changes: 24 additions & 0 deletions src/node-lib/curriculum-api-2023/helpers/zodToCamelCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { z } from "zod";

import { convertKey } from "@/utils/snakeCaseConverter";

// Recursively transform Zod schema keys from snake_case to camelCase
export const zodToCamelCase = <T extends z.ZodTypeAny>(
schema: T,
): z.ZodTypeAny => {
if (!(schema._def.typeName === "ZodObject")) {
throw new Error("zodToCamelCase only works with ZodObject schemas");
}
const transformedShape: Record<string, z.ZodTypeAny> = {};

Object.keys(schema.shape).forEach((key) => {
const camelKey = convertKey(key);
const value = schema.shape[key];

// Recursively transform nested schemas
transformedShape[camelKey] =
value instanceof z.ZodObject ? zodToCamelCase(value) : value;
});

return z.object(transformedShape);
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ProgrammeFields } from "@oaknational/oak-curriculum-schema";

import lessonListingSchema, {
Actions,
LessonListingPageData,
PartialSyntheticUnitvariantLessons,
partialSyntheticUnitvariantLessonsArraySchema,
partialSyntheticUnitvariantLessonsSchema,
} from "./lessonListing.schema";
Expand Down Expand Up @@ -45,7 +45,7 @@ export const getTransformedLessons = (
hasCopyrightMaterial,
orderInUnit: lesson.order_in_unit,
lessonCohort: lesson.lesson_data._cohort,
actions: keysToCamelCase(lesson.actions) || null,
actions: (keysToCamelCase(lesson.actions) || null) as Actions,
};
return transformedLesson;
})
Expand Down Expand Up @@ -79,9 +79,7 @@ export const getPackagedUnit = (

const combinedActions = getIntersection<LessonListSchema[number]["actions"]>(
unitLessons.map((lesson) => lesson.actions),
);

console.log("actions", combinedActions);
) as Actions;

return {
programmeSlug,
Expand Down Expand Up @@ -136,8 +134,9 @@ const lessonListingQuery =
programmeSlugByYear: lesson.programme_slug_by_year,
};
}, {} as PackagedUnitData);
const transformedUnit = getPackagedUnit(packagedUnitData, unitLessons);
return lessonListingSchema.parse(transformedUnit);

const packagedUnit = getPackagedUnit(packagedUnitData, unitLessons);
return lessonListingSchema.parse(packagedUnit);
};

export default lessonListingQuery;
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import { z } from "zod";
import {
programmeFieldsSchema,
syntheticUnitvariantLessonsSchema,
actionsSchema,
} from "@oaknational/oak-curriculum-schema";

import { lessonListSchema } from "../../shared.schema";
import { zodToCamelCase } from "../../helpers/zodToCamelCase";

const camelActionSchema = zodToCamelCase(actionsSchema) as typeof actionsSchema;

export type Actions = z.infer<typeof camelActionSchema>;

const lessonListingSchema = z.object({
programmeSlug: z.string(),
Expand All @@ -24,7 +30,7 @@ const lessonListingSchema = z.object({
pathwayTitle: programmeFieldsSchema.shape.pathway,
pathwayDisplayOrder: programmeFieldsSchema.shape.pathway_display_order,
lessons: lessonListSchema,
actions: z.object({}).nullable(),
actions: camelActionSchema,
});

export type lessonListingSchema = z.infer<typeof lessonListingSchema>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import { KeyStageTitleValueType } from "@/browser-lib/avo/Avo";
import useAnalytics from "@/context/Analytics/useAnalytics";
import { NEW_COHORT } from "@/config/cohort";
import { SpecialistLesson } from "@/node-lib/curriculum-api-2023/queries/specialistLessonListing/specialistLessonListing.schema";
import NewContentBanner from "@/components/TeacherComponents/NewContentBanner/NewContentBanner";
import removeLegacySlugSuffix from "@/utils/slugModifiers/removeLegacySlugSuffix";
import isSlugEYFS from "@/utils/slugModifiers/isSlugEYFS";
import PaginationHead from "@/components/SharedComponents/Pagination/PaginationHead";
Expand All @@ -45,7 +44,6 @@ import {
useShareExperiment,
} from "@/pages-helpers/teacher/share-experiments/useShareExperiment";
import { TeacherShareButton } from "@/components/TeacherComponents/TeacherShareButton/TeacherShareButton";
import { act } from "@testing-library/react";

export type LessonListingPageProps = {
curriculumData: LessonListingPageData;
Expand Down Expand Up @@ -78,12 +76,9 @@ const LessonListPage: NextPage<LessonListingPageProps> = ({
subjectTitle,
programmeSlug,
subjectSlug,
actions,
// actions,
} = curriculumData;

// TODO why is this not passed through?
console.log({ actions });

const { shareExperimentFlag, shareUrl, browserUrl, shareActivated } =
useShareExperiment({
unitSlug: unitSlug ?? undefined,
Expand Down Expand Up @@ -224,13 +219,13 @@ const LessonListPage: NextPage<LessonListingPageProps> = ({
<MaxWidth $ph={16}>
<OakGrid>
<OakGridArea $colSpan={[12, 9]}>
<NewContentBanner
{/* <NewContentBanner
keyStageSlug={keyStageSlug}
subjectSlug={subjectSlug}
subjectTitle={subjectTitle.toLowerCase()}
programmeSlug={programmeSlug}
isLegacy={isSlugLegacy(programmeSlug)}
/>
/> */}
</OakGridArea>
</OakGrid>
<OakGrid>
Expand Down

0 comments on commit 5653d18

Please sign in to comment.