Skip to content

Commit

Permalink
fix: invalid types after migrating campusdish schemas to match prisma…
Browse files Browse the repository at this point in the history
… schema
  • Loading branch information
anmho committed Feb 5, 2024
1 parent 860adfd commit 5335282
Show file tree
Hide file tree
Showing 20 changed files with 10,409 additions and 5,057 deletions.
Empty file added .turbo/cookies/1.cookie
Empty file.
Empty file added .turbo/cookies/2.cookie
Empty file.
Empty file added .turbo/cookies/3.cookie
Empty file.
Empty file added .turbo/cookies/4.cookie
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion apps/lambda/package.json → apps/server/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "lambda",
"name": "server",
"version": "1.0.0",
"description": "Serverless aws-nodejs-typescript template",
"main": "serverless.ts",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@trpc/server": "11.0.0-next-beta.236",
"@zotmeal/db": "workspace:^",
"@zotmeal/eslint-config": "workspace:^",
"@zotmeal/prettier-config": "workspace:^",
"@zotmeal/tsconfig": "workspace:^",
"@zotmeal/utils": "workspace:^",
"@zotmeal/validators": "workspace:^",
Expand Down
17 changes: 15 additions & 2 deletions packages/api/src/router/menu/parse.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { describe, expect, it } from "vitest";

import data from "./campus_dish_schema.json";
import { CampusDishResponseSchema } from "@zotmeal/validators";

import campus_dish_response from "./campus_dish_response.json";
import { parseCampusDish } from "./parse";

describe("parse campus dish", () => {
it("parses campus dish response", () => {
expect(parseCampusDish(data)).not.toBeNull();
expect(() => {
const validated = CampusDishResponseSchema.parse(campus_dish_response);
// open a db instance
const menu = parseCampusDish(validated);
console.log(menu);

expect(menu).not.toBeNull();
}).not.toThrow();
});

it("", () => {
// add an integration test, ideally using testcontainers
});
});
165 changes: 83 additions & 82 deletions packages/api/src/router/menu/parse.ts
Original file line number Diff line number Diff line change
@@ -1,107 +1,108 @@
import axios from "axios";
import { z } from "zod";

import type { Menu } from "@zotmeal/db";
import type {
// CampusDishMenuStation,
CampusDishResponse,
// ParsedResponse,
DietRestrictionSchema,
DishSchema,
} from "@zotmeal/validators";
import { getPeriodId, getRestaurantId } from "@zotmeal/utils";
import {
getPeriodId,
getRestaurantById,
getRestaurantId,
} from "@zotmeal/utils";
import { CampusDishResponseSchema } from "@zotmeal/validators";

import { publicProcedure } from "../../trpc";
import { GetMenuSchema } from "./get";

// We will examine the response and update our database state
// Add new dishes
// Add new menu
// Add new hours
export function parseCampusDish(data: Record<string, unknown>): Menu | null {
const response = CampusDishResponseSchema.parse(data);
if (response === null) {
return null;
}
console.log(response);
// we should get a menu object with a full nested hierarchy
// we want to return a menu tree
// validate schema with zod
// fail if it does not match
export const parseMenuProcedure = publicProcedure
// .input(GetMenuSchema)
.query(async ({ ctx, input }) => {
const { db } = ctx;
const _ = db;
// const { date, restaurant, period } = input;

// const periodId = getPeriodId(period);
// const restaurantId = getRestaurantId(restaurant);

const res = await axios.get(
"https://uci-campusdish-com.translate.goog/api/menu/GetMenus?locationId=3314&periodId=49&date=1/19/2024",
);
// const res = await axios.get(
// `https://uci-campusdish-com.translate.goog/api/menu/GetMenus?locationId=${restaurantId}&periodId=${periodId}&date=${date}`,
// );
try {
const validated = CampusDishResponseSchema.parse(res);
} catch (e) {
console.log(e);
throw e;
}

const menu = parseCampusDish(validated);

return menu;
});

export function parseCampusDish(response: CampusDishResponse) {
const uniqueStations = new Set<string>();
response.Menu.MenuStations.forEach((menuStation) => {
uniqueStations.add(
JSON.stringify({
station_id: menuStation.StationId,
restaurant_id: data.LocationId,
restaurant_id: response.LocationId,
name: menuStation.Name,
}),
);
});

// const stations = Array.from(uniqueStations).map(
// (station) => JSON.parse(station) as CampusDishMenuStation,
// );

// // prefetch the periods

// const parsed = {
// restaurant: {
// restaurant_id: data.LocationId,
// restaurant_name:
// LocationNames[data.LocationId as keyof typeof LocationNames],
// },
// stations,
// dishes: data.Menu.MenuProducts.map((menuProduct) => ({
// id: menuProduct.Product.ProductId,
// station_id: menuProduct.StationId,
// name: menuProduct.Product.MarketingName,
// description: menuProduct.Product.ShortDescription,
// dietary_restriction_info: {
// id: menuProduct.Product.ProductId,
// contains_eggs: menuProduct.Product.ContainsEggs,
// contains_fish: menuProduct.Product.ContainsFish,
// contains_milk: menuProduct.Product.ContainsMilk,
// contains_peanuts: menuProduct.Product.ContainsPeanuts,
// contains_shellfish: menuProduct.Product.ContainsShellfish,
// contains_soy: menuProduct.Product.ContainsSoy,
// contains_tree_nuts: menuProduct.Product.ContainsTreeNuts,
// contains_wheat: menuProduct.Product.ContainsWheat,
// contains_sesame: menuProduct.Product.ContainsSesame,
// is_gluten_free: menuProduct.Product.IsGlutenFree,
// is_halal: menuProduct.Product.IsHalal,
// is_kosher: menuProduct.Product.IsKosher,
// is_locally_grown: menuProduct.Product.IsLocallyGrown,
// is_organic: menuProduct.Product.IsOrganic,
// is_vegan: menuProduct.Product.IsVegan,
// is_vegetarian: menuProduct.Product.IsVegetarian,
// },
// })),
// };
return null;
}

export const parseMenuProcedure = publicProcedure
.input(GetMenuSchema)
.query(async ({ input }) => {
const { date, restaurant, period } = input;

// get the period by name from the db

// use the db as the source of truth

const periodId = getPeriodId(period);
const restaurantId = getRestaurantId(restaurant);
const stations = Array.from(uniqueStations).map(
(station) =>
JSON.parse(station) as {
station_id: string;
restaurant_id: string;
name: string;
},
);

// const res = await axios.get(
// "https://uci-campusdish-com.translate.goog/api/menu/GetMenus?locationId=3314&periodId=49&date=1/19/2024",
// );
const res = await axios.get(
`https://uci-campusdish-com.translate.goog/api/menu/GetMenus?locationId=${restaurantId}&periodId=${periodId}&date=${date}`,
);

const data = res.data as CampusDishResponse;
const dishes = response.Menu.MenuProducts.map((menuProduct) => {
type DietRestriction = z.infer<typeof DietRestrictionSchema>;
const dietRestriction = {
containsEggs: menuProduct.Product.ContainsEggs,
containsFish: menuProduct.Product.ContainsFish,
containsMilk: menuProduct.Product.ContainsMilk,
containsPeanuts: menuProduct.Product.ContainsPeanuts,
containsShellfish: menuProduct.Product.ContainsShellfish,
containsSoy: menuProduct.Product.ContainsSoy,
containsTreeNuts: menuProduct.Product.ContainsTreeNuts,
containsWheat: menuProduct.Product.ContainsWheat,
containsSesame: menuProduct.Product.ContainsSesame,
isGlutenFree: menuProduct.Product.IsGlutenFree,
isHalal: menuProduct.Product.IsHalal,
isKosher: menuProduct.Product.IsKosher,
isLocallyGrown: menuProduct.Product.IsLocallyGrown,
isOrganic: menuProduct.Product.IsOrganic,
isVegan: menuProduct.Product.IsVegan,
isVegetarian: menuProduct.Product.IsVegetarian,
} as DietRestriction;

// parseCampusDish(data);
type Dish = z.infer<typeof DishSchema>;

return data;
return {
id: menuProduct.MenuProductId,
stationId: menuProduct.StationId,
name: menuProduct.Product.MarketingName,
description: menuProduct.Product.ShortDescription,
dietRestriction: dietRestriction,
} as Dish;
});
const parsed = {
restaurant: {
restaurant_id: response.LocationId,
restaurant_name: getRestaurantById(response.LocationId),
},
stations,
dishes: dishes,
};
return parsed;
}
51 changes: 44 additions & 7 deletions packages/utils/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,65 @@ import type { MenuPeriod, RestaurantName } from "@zotmeal/db";
// id mappings (period, restaurant)
// restaurant names

const restaurantToId = {
function invertMapping(
mapping: Record<string, string>,
): Record<string, string> {
const inverted = {} as Record<string, string>;
for (const key in mapping) {
const value = mapping[key]!;
inverted[value] = key;
}

return inverted;
}

const RESTAURANT_TO_ID = {
brandywine: "3314",
anteatery: "3056",
} as const;
const ID_TO_RESTAURANT = invertMapping(RESTAURANT_TO_ID);

export const getRestaurantId = (restaurant: RestaurantName): string | null => {
if (!(restaurant in restaurantToId)) {
if (!(restaurant in RESTAURANT_TO_ID)) {
return null;
}

return RESTAURANT_TO_ID[restaurant];
};

export const getRestaurantById = (
id: keyof typeof ID_TO_RESTAURANT,
): RestaurantName | null => {
if (!(id in ID_TO_RESTAURANT)) {
return null;
}

return restaurantToId[restaurant];
return ID_TO_RESTAURANT[id] as RestaurantName;
};

const periodToId = {
const PERIOD_TO_ID = {
breakfast: "49",
lunch: "106",
dinner: "107",
brunch: "2651",
latenight: "108",
} as const;
const ID_TO_PERIOD = invertMapping(PERIOD_TO_ID);

export const getPeriodId = (period: MenuPeriod): string | null => {
if (!(period in periodToId)) return null;
export const getPeriodId = (
period: MenuPeriod,
): keyof typeof ID_TO_PERIOD | null => {
if (!(period in PERIOD_TO_ID)) return null;

return PERIOD_TO_ID[period];
};

export const getPeriodById = (
id: keyof typeof ID_TO_PERIOD,
): MenuPeriod | null => {
if (!(id in ID_TO_PERIOD)) {
return null;
}

return periodToId[period];
return ID_TO_PERIOD[id];
};
2 changes: 0 additions & 2 deletions packages/validators/src/zotmeal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { z } from "zod";

export const DietRestrictionSchema = z.object({
id: z.string(),
containsEggs: z.boolean().nullable(),
containsFish: z.boolean().nullable(),
containsMilk: z.boolean().nullable(),
Expand Down Expand Up @@ -61,7 +60,6 @@ export const StationSchema = z.object({
name: z.string(),
});


export const MenuPeriodSchema = z.object({
id: z.string(),
name: z.string(),
Expand Down
Loading

0 comments on commit 5335282

Please sign in to comment.