From d8a9f9ecf72404f8913500bfd3fac3529faf3502 Mon Sep 17 00:00:00 2001 From: Adam Garcia Date: Wed, 24 May 2023 21:12:49 -0400 Subject: [PATCH] Adding Basic Database Seeding (#73) * Added Migration * Work on seeding DB * I think team/event linking working * Finished seeding function for teams/events * Applied linting * fix prisma datatype * Event improvement * Added basic utils page to trigger Seeding * Added prisma migrate github action * Testing * Formatting * Fixed lodash types --------- Co-authored-by: Adam Garcia Co-authored-by: warren yun --- .github/workflows/prismaMigrate.yml | 72 ++++++ components/navbar/index.tsx | 1 + lib/fetchTBA.ts | 58 +++++ package.json | 3 + pages/api/events/infoTeams.ts | 16 +- pages/api/utils/seed.ts | 238 ++++++++++++++++++ pages/api/v2/event/matches.ts | 32 +-- pages/events/[event]/index.tsx | 80 ++++-- pages/events/index.tsx | 1 + pages/utils.tsx | 25 ++ .../migration.sql | 25 ++ .../20230524035453_added_teams/migration.sql | 46 ++++ .../20230524162556_changes/migration.sql | 36 +++ .../20230524163308_webcasts/migration.sql | 9 + prisma/schema.prisma | 13 +- yarn.lock | 12 +- 16 files changed, 604 insertions(+), 63 deletions(-) create mode 100644 .github/workflows/prismaMigrate.yml create mode 100644 pages/api/utils/seed.ts create mode 100644 pages/utils.tsx create mode 100644 prisma/migrations/20230523195143_new_migration/migration.sql create mode 100644 prisma/migrations/20230524035453_added_teams/migration.sql create mode 100644 prisma/migrations/20230524162556_changes/migration.sql create mode 100644 prisma/migrations/20230524163308_webcasts/migration.sql diff --git a/.github/workflows/prismaMigrate.yml b/.github/workflows/prismaMigrate.yml new file mode 100644 index 0000000..150fa22 --- /dev/null +++ b/.github/workflows/prismaMigrate.yml @@ -0,0 +1,72 @@ +name: Prisma Migrate +# https://blog.henriktech.com/deploying-prisma-migrations-via-github-actions + +on: + push: + branches: [staging] + paths: + - "./prisma/**/*.*" + pull_request: + +jobs: + install: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup Nodejs + uses: actions/setup-node@v2 + with: + node-version: 16.x + cache: "yarn" + + - name: Install + run: yarn install + - name: Rerun Install + run: yarn install + + generate: + runs-on: ubuntu-latest + + needs: install + + steps: + - uses: actions/checkout@v2 + + - name: Setup Nodejs + uses: actions/setup-node@v2 + with: + node-version: 16.x + cache: "yarn" + + - name: Install + run: yarn install + + - run: rm -rf node_modules/.prisma + + - name: Generate Prisma Client + run: npx prisma generate + + # migrate: + # runs-on: ubuntu-latest + + # needs: install + + # steps: + # - uses: actions/checkout@v2 + + # - name: Setup Nodejs + # uses: actions/setup-node@v2 + # with: + # node-version: 16.x + # cache: "yarn" + + # - name: Install + # run: yarn install + + # - run: rm -rf node_modules/.prisma + + # - name: Deploy Migrations + # run: npx prisma migrate deploy + # env: + # DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }} diff --git a/components/navbar/index.tsx b/components/navbar/index.tsx index ff15dd4..0e30cb0 100644 --- a/components/navbar/index.tsx +++ b/components/navbar/index.tsx @@ -44,6 +44,7 @@ const links: { title: string; href: string; icon: JSX.Element }[] = [ { title: "Rookie Teams", href: "/rookies", icon: }, { title: "Insights", href: "/insights", icon: }, { title: "Marketplace", href: "/marketplace", icon: }, + { title: "Utils", href: "/utils", icon: }, ]; export const Navbar = (props: { diff --git a/lib/fetchTBA.ts b/lib/fetchTBA.ts index e414168..6a2e58c 100644 --- a/lib/fetchTBA.ts +++ b/lib/fetchTBA.ts @@ -23,3 +23,61 @@ export const fetchTBA = async ( .then((response: AxiosResponse) => response.data) .catch((error) => log("error", error)); }; + +export type TBATeam = { + key: string; + team_number: number; + nickname?: string; + name: string; + city?: string; + state_prov?: string; + country?: string; + address?: string; + postal_code?: string; + gmaps_place_id?: string; + gmaps_url?: string; + lat?: number; + lng?: number; + location_name?: string; + website?: string; + rookie_year?: number; + motto?: string; +}; + +export type TBAEvent = { + key: string; + name: string; + event_code: string; + event_type: number; + // district?: + city?: string; + state_prov?: string; + country?: string; + start_date: string; + end_date: string; + year: number; + short_name?: string; + event_type_string: string; + week?: number; + address?: string; + postal_code?: string; + gmaps_place_id?: string; + gmaps_url?: string; + lat?: number; + lng?: number; + location_name?: string; + timezone?: string; + website?: string; + first_event_id?: string; + first_event_code?: string; + webcasts?: { + channel: string; + type: string; + date?: string; + file?: string; + }[]; + divison_keys?: string[]; + parent_event_key?: string; + playoff_type?: number; + playoff_type_string?: string; +}; diff --git a/package.json b/package.json index 9df4add..03a1522 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,9 @@ "export-from-json": "^1.7.2", "framer-motion": "^10.12.14", "haversine-distance": "^1.2.1", + "lodash": "^4.17.21", "next": "13.4.3", + "next-api-handler": "^0.4.10", "next-auth": "^4.22.1", "next-s3-upload": "^0.3.0", "nsfwjs": "^2.4.2", @@ -54,6 +56,7 @@ "devDependencies": { "@commitlint/cli": "^17.6.3", "@commitlint/config-conventional": "^17.6.3", + "@types/lodash": "^4.14.194", "husky": "^8.0.3", "prettier": "^2.8.8" }, diff --git a/pages/api/events/infoTeams.ts b/pages/api/events/infoTeams.ts index 16fe2e9..d5c7931 100644 --- a/pages/api/events/infoTeams.ts +++ b/pages/api/events/infoTeams.ts @@ -1,15 +1,23 @@ import { NextApiRequest, NextApiResponse } from "next"; import { fetchTBA } from "@/lib/fetchTBA"; import { AxiosResponse } from "axios"; +import db from "@/lib/db"; export default async function getEventTeams( req: NextApiRequest, res: NextApiResponse ): Promise { const { event } = req.query; - const data: void | AxiosResponse = await fetchTBA( - `event/${event}/teams` - ); - res.status(200).send(data); + const rest = await db.team.findMany({ + where: { + events: { + some: { + key: event as string, + }, + }, + }, + }); + + res.status(200).send(rest); } diff --git a/pages/api/utils/seed.ts b/pages/api/utils/seed.ts new file mode 100644 index 0000000..51a0454 --- /dev/null +++ b/pages/api/utils/seed.ts @@ -0,0 +1,238 @@ +import { tbaAxios, TBAEvent, TBATeam } from "@/lib/fetchTBA"; +import { RouterBuilder } from "next-api-handler"; +import db from "@/lib/db"; +import _ from "lodash"; +import { Team, Event, Prisma } from "@prisma/client"; + +const router = new RouterBuilder(); + +const handleTeamsETL = async () => { + console.log("Starting Teams ETL"); + + let numTeamsInserted = 0; + let pageNum = 0; + while (true) { + const teamsRequest = await tbaAxios.get(`/teams/${pageNum}`); + if (teamsRequest.data.length === 0) { + break; + } + console.log( + `Parsing Teams page ${pageNum++}. Found ${ + teamsRequest.data.length + } Teams. [${teamsRequest.data[0].team_number}/${ + teamsRequest.data[teamsRequest.data.length - 1].team_number + }]` + ); + + const data = teamsRequest.data.map((team): Team => { + return { + team_number: team.team_number, + city: team.city ?? null, + country: team.country ?? null, + nickname: team.nickname ?? null, + website: team.website ?? null, + state_prov: team.state_prov ?? null, + rookie_year: team.rookie_year ?? null, + name: team.name, + address: team.address ?? null, + postal_code: team.postal_code ?? null, + lat: team.lat ?? null, + lng: team.lng ?? null, + location_name: team.location_name ?? null, + gmaps_place_id: team.gmaps_place_id ?? null, + gmaps_url: team.gmaps_url ?? null, + motto: team.motto ?? null, + key: team.key, + school_name: null, + }; + }); + + const result = await db.team.createMany({ + data, + skipDuplicates: true, + }); + + numTeamsInserted += result.count; + } + + console.log("Finished Teams ETL"); + return numTeamsInserted; +}; + +const handleEventsETL = async () => { + console.log("Starting Events ETL"); + + const startYear = 2019; + const endYear = 2023; + + let numEventsInserted = 0; + + // "address": "700 Monroe St SW, Huntsville, AL 35801, USA", + // "city": "Huntsville", + // "country": "USA", + // "district": null, + // "division_keys": [], + // "end_date": "2023-04-08", + // "event_code": "alhu", + // "event_type": 0, + // "event_type_string": "Regional", + // "first_event_code": "alhu", + // "first_event_id": null, + // "gmaps_place_id": "ChIJBwUw_FdrYogRMsP0V0W5Zqk", + // "gmaps_url": "https://maps.google.com/?q=700+Monroe+St+SW,+Huntsville,+AL+35801,+USA&ftid=0x88626b57fc300507:0xa966b94557f4c332", + // "key": "2023alhu", + // "lat": 34.72671, + // "lng": -86.5903795, + // "location_name": "700 Monroe St SW", + // "name": "Rocket City Regional", + // "parent_event_key": null, + // "playoff_type": 10, + // "playoff_type_string": "Double Elimination Bracket (8 Alliances)", + // "postal_code": "35801", + // "short_name": "Rocket City", + // "start_date": "2023-04-05", + // "state_prov": "AL", + // "timezone": "America/Chicago", + // "webcasts": [ + // { + // "channel": "firstinspires13", + // "type": "twitch" + // }, + // { + // "channel": "firstinspires14", + // "type": "twitch" + // } + // ], + // "website": "http://firstinalabama.org/events/frc-events/", + // "week": 5, + // "year": 2023 + for (let year = startYear; year <= endYear; year++) { + console.log(`Parsing Events for ${year}`); + const eventsRequest = await tbaAxios.get(`/events/${year}`); + console.log(`Found ${eventsRequest.data.length} Events for ${year}`); + + const data = eventsRequest.data.map((event): Event => { + return { + key: event.key, + name: event.name, + short_name: event.short_name ?? null, + event_type: event.event_type, + event_type_string: event.event_type_string, + // district: event.district?.display_name ?? null, + city: event.city ?? null, + state_prov: event.state_prov ?? null, + country: event.country ?? null, + start_date: event.start_date, + end_date: event.end_date, + year: event.year, + website: event.website ?? null, + postal_code: event.postal_code ?? null, + lat: event.lat ?? null, + lng: event.lng ?? null, + location_name: event.location_name ?? null, + gmaps_place_id: event.gmaps_place_id ?? null, + gmaps_url: event.gmaps_url ?? null, + timezone: event.timezone ?? null, + week: event.week ?? null, + parent_event_key: event.parent_event_key ?? null, + playoff_type: event.playoff_type ?? null, + playoff_type_string: event.playoff_type_string ?? null, + first_event_id: event.first_event_id ?? null, + first_event_code: event.first_event_code ?? null, + division_keys: event.divison_keys ?? [], + address: event.address ?? null, + event_code: event.event_code, + webcasts: (event.webcasts as Prisma.JsonArray) ?? null, + }; + }); + + const result = await db.event.createMany({ + // Not sure why data mismatch + data: data as any, + skipDuplicates: true, + }); + + numEventsInserted += result.count; + } + + console.log("Finished Events ETL"); +}; + +const addTeamsToEvents = async () => { + console.log("Starting Teams to Events ETL"); + + const allEvents = await db.event.findMany({ + select: { + key: true, + }, + }); + + const eventPromiseArr = allEvents.map((event) => async () => { + try { + const participatingTeams = await tbaAxios.get( + `/event/${event.key}/teams/keys` + ); + + await db.event.update({ + where: { + key: event.key, + }, + data: { + teams: { + connect: participatingTeams.data.map((teamKey: string) => { + return { + team_number: parseInt(teamKey.substring(3)), + }; + }), + }, + }, + }); + + return event.key; + } catch (error) { + console.log("Error adding teams to event: ", event.key); + console.log(error); + return undefined; + } + }); + + // Chunk the promises to avoid overloading the DB + const chunkedPromises = _.chunk(eventPromiseArr, 50); + console.log(`Splitting Events into ${chunkedPromises.length} chunks`); + + // loop over chunkedPromises with index + for (const [index, eventPromise] of chunkedPromises.entries()) { + const allEvents = await Promise.all( + eventPromise.map((fn: Function) => fn()) + ); + console.log( + `Event Chunk: ${index + 1}/${ + chunkedPromises.length + }. Added the following events: ${allEvents + .filter((event) => event !== undefined) + .join(", ")}` + ); + } + + return true; +}; + +router.post(async (req, res) => { + // First download all teams + try { + const teamsInserted = await handleTeamsETL(); + const eventsInserted = await handleEventsETL(); + await addTeamsToEvents(); + + res.status(200).json({ + message: "Success", + teamsInserted, + eventsInserted, + // teamsInserted + }); + } catch (error) { + console.log("error: ", error); + } +}); + +export default router.build(); diff --git a/pages/api/v2/event/matches.ts b/pages/api/v2/event/matches.ts index 2bf4f39..6bc4dda 100644 --- a/pages/api/v2/event/matches.ts +++ b/pages/api/v2/event/matches.ts @@ -2,48 +2,20 @@ import { NextApiRequest, NextApiResponse } from "next"; import { fetchTBA } from "@/lib/fetchTBA"; import db from "@/lib/db"; -export default async function getEventRankings( +export default async function getMatches( req: NextApiRequest, res: NextApiResponse ): Promise { try { const { event } = req.query; - const matches: any = await fetchTBA(`event/${event}/matches`); const eventMatches = await db.match.findMany({ where: { event_key: String(event), }, }); - if (eventMatches.length > 0) { - res.status(200).send(eventMatches); - } else { - const createdMatches = await Promise.allSettled( - matches.map(async (match: any) => { - try { - const createdMatch = await db.match.upsert({ - where: { - key: match.key, - }, - create: { - ...match, - }, - update: {}, - }); - return { status: "fulfilled", value: createdMatch }; - } catch (error) { - return { status: "rejected", reason: error }; - } - }) - ); - - const successfulMatches = createdMatches - .filter((result) => result.status === "fulfilled") - .map((result) => (result as PromiseFulfilledResult).value); - - res.status(200).send((successfulMatches as any).value); - } + return res.status(200).send(eventMatches); } catch { res.status(400).send("Error"); } diff --git a/pages/events/[event]/index.tsx b/pages/events/[event]/index.tsx index 09eb9d7..ece1d3b 100644 --- a/pages/events/[event]/index.tsx +++ b/pages/events/[event]/index.tsx @@ -130,35 +130,73 @@ export const getServerSideProps: GetServerSideProps = async ( ): Promise => { const { event }: any = context.params; + const t1 = performance.now(); + const session: Session = (await getServerSession( context.req, context.res, authOptions )) as Session; - const matches = await fetch( - `${API_URL}/api/v2/event/matches?event=${event}` - ).then((res) => res.json()); + const t2 = performance.now(); - const eventInfo = await db.event.findUnique({ - where: { - key: String(event), - }, - }); + console.log(`Took ${t2 - t1}ms to get session`); + + const [matches, eventInfo, eventTeams, eventAlliances] = await Promise.all([ + fetch(`${API_URL}/api/v2/event/matches?event=${event}`).then((res) => + res.json() + ), + db.event.findUnique({ + where: { + key: String(event), + }, + }), + fetch(`${API_URL}/api/events/infoTeams?event=${event}`).then((res) => + res.json() + ), + fetch(`${API_URL}/api/events/alliances?event=${event}`).then((res) => + res.json() + ), + ]); + // const matches = await fetch( + // `${API_URL}/api/v2/event/matches?event=${event}` + // ).then((res) => res.json()); + + const t3 = performance.now(); + + console.log(`Took ${t3 - t2}ms to get matches`); + + // const eventInfo = await ; + + const t4 = performance.now(); + + console.log(`Took ${t4 - t3}ms to get event info`); + + // const eventTeams = await fetch( + // `${API_URL}/api/events/infoTeams?event=${event}` + // ).then((res: Response) => res.json()); + + const t5 = performance.now(); + + console.log(`Took ${t5 - t4}ms to get event teams`); + + // const eventAlliances = await fetch( + // `${API_URL}/api/events/alliances?event=${event}` + // ) + // .then((res: Response) => res.json()) + // .catch((): null => null); + + const t6 = performance.now(); + + console.log(`Took ${t6 - t5}ms to get event alliances`); - const eventTeams = await fetch( - `${API_URL}/api/events/infoTeams?event=${event}` - ).then((res: Response) => res.json()); + // const eventAwards = await fetch( + // `${API_URL}/api/events/awards?event=${event.substring(4)}` + // ).then((res: Response) => res.json()); - const eventAlliances = await fetch( - `${API_URL}/api/events/alliances?event=${event}` - ) - .then((res: Response) => res.json()) - .catch((): null => null); + const t7 = performance.now(); - const eventAwards = await fetch( - `${API_URL}/api/events/awards?event=${event.substring(4)}` - ).then((res: Response) => res.json()); + console.log(`Took ${t7 - t6}ms to get event awards`); if (session) { const user: (User & { favouritedTeams: FavouritedTeam[] }) | null = @@ -179,7 +217,7 @@ export const getServerSideProps: GetServerSideProps = async ( eventInfo, eventTeams, eventAlliances, - eventAwards, + eventAwards: [], }, }; } @@ -190,7 +228,7 @@ export const getServerSideProps: GetServerSideProps = async ( eventInfo, eventTeams, eventAlliances, - eventAwards, + eventAwards: [], }, }; }; diff --git a/pages/events/index.tsx b/pages/events/index.tsx index b8e4a6a..f89319f 100644 --- a/pages/events/index.tsx +++ b/pages/events/index.tsx @@ -38,6 +38,7 @@ export const getServerSideProps: GetServerSideProps = async (): Promise<{ props: { events: any }; }> => { const events = await db.event.findMany(); + console.log(events); const sortedEvents = events.sort((a: any, b: any) => a.start_date.localeCompare(b.start_date) ); diff --git a/pages/utils.tsx b/pages/utils.tsx new file mode 100644 index 0000000..923863b --- /dev/null +++ b/pages/utils.tsx @@ -0,0 +1,25 @@ +import { Navbar } from "@/components/navbar"; +import axios from "axios"; +import { JSX, useState } from "react"; + +export default function OnboardingPage(): JSX.Element { + const [isOnboardingModalOpen, setIsOnboardingModalOpen] = useState(true); + + return ( + <> + +
+ +
+ + ); +} diff --git a/prisma/migrations/20230523195143_new_migration/migration.sql b/prisma/migrations/20230523195143_new_migration/migration.sql new file mode 100644 index 0000000..1f99b79 --- /dev/null +++ b/prisma/migrations/20230523195143_new_migration/migration.sql @@ -0,0 +1,25 @@ +-- CreateTable +CREATE TABLE "Match" ( + "id" SERIAL NOT NULL, + "key" TEXT NOT NULL, + "comp_level" TEXT NOT NULL, + "set_number" INTEGER NOT NULL, + "match_number" INTEGER NOT NULL, + "alliances" JSONB, + "winning_alliance" TEXT NOT NULL, + "event_key" TEXT NOT NULL, + "time" INTEGER NOT NULL, + "actual_time" INTEGER NOT NULL, + "predicted_time" INTEGER NOT NULL, + "post_result_time" INTEGER NOT NULL, + "score_breakdown" JSONB, + "videos" JSONB, + + CONSTRAINT "Match_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Match_key_key" ON "Match"("key"); + +-- AddForeignKey +ALTER TABLE "Match" ADD CONSTRAINT "Match_event_key_fkey" FOREIGN KEY ("event_key") REFERENCES "Event"("key") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20230524035453_added_teams/migration.sql b/prisma/migrations/20230524035453_added_teams/migration.sql new file mode 100644 index 0000000..50a35d9 --- /dev/null +++ b/prisma/migrations/20230524035453_added_teams/migration.sql @@ -0,0 +1,46 @@ +/* + Warnings: + + - Added the required column `country` to the `Team` table without a default value. This is not possible if the table is not empty. + - Added the required column `key` to the `Team` table without a default value. This is not possible if the table is not empty. + - Added the required column `nickname` to the `Team` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Event" ADD COLUMN "webcasts" JSONB; + +-- AlterTable +ALTER TABLE "Team" ADD COLUMN "address" TEXT, +ADD COLUMN "city" TEXT, +ADD COLUMN "country" TEXT NOT NULL, +ADD COLUMN "eventKey" TEXT, +ADD COLUMN "gmaps_place_id" TEXT, +ADD COLUMN "gmaps_url" TEXT, +ADD COLUMN "key" TEXT NOT NULL, +ADD COLUMN "lat" INTEGER, +ADD COLUMN "lng" INTEGER, +ADD COLUMN "location_name" TEXT, +ADD COLUMN "motto" TEXT, +ADD COLUMN "name" TEXT, +ADD COLUMN "nickname" TEXT NOT NULL, +ADD COLUMN "postal_code" TEXT, +ADD COLUMN "rookie_year" INTEGER, +ADD COLUMN "school_name" TEXT, +ADD COLUMN "state_prov" TEXT, +ADD COLUMN "website" TEXT; + +-- CreateTable +CREATE TABLE "ApiKey" ( + "id" SERIAL NOT NULL, + "key" TEXT NOT NULL, + "userId" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "ApiKey_key_key" ON "ApiKey"("key"); + +-- AddForeignKey +ALTER TABLE "Team" ADD CONSTRAINT "Team_eventKey_fkey" FOREIGN KEY ("eventKey") REFERENCES "Event"("key") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ApiKey" ADD CONSTRAINT "ApiKey_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20230524162556_changes/migration.sql b/prisma/migrations/20230524162556_changes/migration.sql new file mode 100644 index 0000000..75a1a28 --- /dev/null +++ b/prisma/migrations/20230524162556_changes/migration.sql @@ -0,0 +1,36 @@ +/* + Warnings: + + - You are about to drop the column `eventKey` on the `Team` table. All the data in the column will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "Team" DROP CONSTRAINT "Team_eventKey_fkey"; + +-- AlterTable +ALTER TABLE "Event" ALTER COLUMN "city" DROP NOT NULL, +ALTER COLUMN "state_prov" DROP NOT NULL, +ALTER COLUMN "country" DROP NOT NULL; + +-- AlterTable +ALTER TABLE "Team" DROP COLUMN "eventKey", +ALTER COLUMN "country" DROP NOT NULL, +ALTER COLUMN "nickname" DROP NOT NULL; + +-- CreateTable +CREATE TABLE "_EventToTeam" ( + "A" TEXT NOT NULL, + "B" INTEGER NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "_EventToTeam_AB_unique" ON "_EventToTeam"("A", "B"); + +-- CreateIndex +CREATE INDEX "_EventToTeam_B_index" ON "_EventToTeam"("B"); + +-- AddForeignKey +ALTER TABLE "_EventToTeam" ADD CONSTRAINT "_EventToTeam_A_fkey" FOREIGN KEY ("A") REFERENCES "Event"("key") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_EventToTeam" ADD CONSTRAINT "_EventToTeam_B_fkey" FOREIGN KEY ("B") REFERENCES "Team"("team_number") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20230524163308_webcasts/migration.sql b/prisma/migrations/20230524163308_webcasts/migration.sql new file mode 100644 index 0000000..0ee0d47 --- /dev/null +++ b/prisma/migrations/20230524163308_webcasts/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - The `webcasts` column on the `Event` table would be dropped and recreated. This will lead to data loss if there is data in the column. + +*/ +-- AlterTable +ALTER TABLE "Event" DROP COLUMN "webcasts", +ADD COLUMN "webcasts" JSONB[]; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5c8be76..74ef2bf 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -132,15 +132,14 @@ model Team { location_name String? motto String? name String? - nickname String + nickname String? postal_code String? rookie_year Int? school_name String? state_prov String? website String? socials Social[] - Event Event? @relation(fields: [eventKey], references: [key]) - eventKey String? + events Event[] } model Social { @@ -158,9 +157,9 @@ model Event { name String event_code String event_type Int - city String - state_prov String - country String + city String? + state_prov String? + country String? start_date String end_date String year Int @@ -178,7 +177,7 @@ model Event { website String? first_event_id String? first_event_code String? - webcasts Json? + webcasts Json[] division_keys String[] parent_event_key String? playoff_type Int? diff --git a/yarn.lock b/yarn.lock index 7bdfa6c..9525c3f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1553,6 +1553,11 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/lodash@^4.14.194": + version "4.14.194" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76" + integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g== + "@types/long@^4.0.1": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" @@ -3902,7 +3907,7 @@ lodash.upperfirst@^4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== -lodash@^4.17.15: +lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4104,6 +4109,11 @@ ndarray@^1.0.13: iota-array "^1.0.0" is-buffer "^1.0.2" +next-api-handler@^0.4.10: + version "0.4.10" + resolved "https://registry.yarnpkg.com/next-api-handler/-/next-api-handler-0.4.10.tgz#ff41a28af653ff4f912ace11504bf38ed4693a17" + integrity sha512-hC8s+nJK/eIPNPcvT2r72EysfZa9vuVKOgJV1118lbLRx1o8fgm70uUlF6jl7EIbcoGAf0X7DbNY3x9dCLIHzg== + next-auth@^4.22.1: version "4.22.1" resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.22.1.tgz#1ea5084e38867966dc6492a71c6729c8f5cfa96b"