diff --git a/apps/api/src/graphql/resolvers/programs.ts b/apps/api/src/graphql/resolvers/programs.ts index 2b799e11..1a99111e 100644 --- a/apps/api/src/graphql/resolvers/programs.ts +++ b/apps/api/src/graphql/resolvers/programs.ts @@ -20,9 +20,12 @@ export const programResolvers = { const service = new ProgramsService(db); const res = await service.getMajorRequirements(parsedArgs); if (!res) - throw new GraphQLError(`Major ${parsedArgs.programId} not found`, { - extensions: { code: "NOT_FOUND" }, - }); + throw new GraphQLError( + `No requirements found for major ${parsedArgs.programId}${parsedArgs.specializationId ? ` with specialization ${parsedArgs.specializationId}` : ""}.`, + { + extensions: { code: "NOT_FOUND" }, + }, + ); return res; }, minor: async (_: unknown, args: { query?: unknown }, { db }: GraphQLContext) => { diff --git a/apps/api/src/graphql/schema/programs.ts b/apps/api/src/graphql/schema/programs.ts index d8ffadca..e65e3e93 100644 --- a/apps/api/src/graphql/schema/programs.ts +++ b/apps/api/src/graphql/schema/programs.ts @@ -106,6 +106,11 @@ type UgradRequirements @cacheControl(maxAge: 86400) { requirements: [ProgramRequirement!]!, } +input MajorRequirementsQuery { + programId: String! + specializationId: String +} + input ProgramRequirementsQuery { programId: String! } @@ -130,7 +135,7 @@ extend type Query { majors(query: MajorsQuery): [MajorPreview!]! minors(query: MinorsQuery): [MinorPreview!]! specializations(query: SpecializationsQuery): [SpecializationPreview!]! - major(query: ProgramRequirementsQuery!): Major! + major(query: MajorRequirementsQuery!): Major! minor(query: ProgramRequirementsQuery!): Minor! specialization(query: ProgramRequirementsQuery!): Specialization! ugradRequirements(query: UgradRequrementsQuery!): UgradRequirements! diff --git a/apps/api/src/rest/routes/programs.ts b/apps/api/src/rest/routes/programs.ts index 098dbdc6..b1065f5c 100644 --- a/apps/api/src/rest/routes/programs.ts +++ b/apps/api/src/rest/routes/programs.ts @@ -80,9 +80,7 @@ const majorRequirements = createRoute({ tags: ["Programs"], method: "get", path: "/major", - description: - "Retrieve course requirements for a major in UCI's current catalogue. Note that these are the requirements for the major itself; " + - "if this major has specializations, then one is mandatory and its requirements apply as well.", + description: "Retrieve course requirements for a major in UCI's current catalogue.", request: { query: majorRequirementsQuerySchema }, responses: { 200: response200(majorRequirementsResponseSchema), @@ -190,7 +188,8 @@ programsRouter.openapi(majorRequirements, async (c) => { : c.json( { ok: false, - message: "Couldn't find this major; check your ID?", + message: + "Couldn't find major requirements associated with this major and specialization; check your IDs?", }, 404, ); diff --git a/apps/api/src/schema/programs.ts b/apps/api/src/schema/programs.ts index b910069f..9dbc65f5 100644 --- a/apps/api/src/schema/programs.ts +++ b/apps/api/src/schema/programs.ts @@ -30,6 +30,11 @@ export const majorRequirementsQuerySchema = z.object({ description: "A major ID to query requirements for", example: "BS-201", }), + specializationId: programIdBase.optional().openapi({ + description: + "if provided, fetch major requirements given this specialization; providing no specialization when one is required has unspecified behavior", + example: "BS-201A", + }), }); export const minorRequirementsQuerySchema = z.object({ @@ -200,8 +205,7 @@ export const majorsResponseSchema = z.array( description: "Whether a specialization must be completed to complete this degree", }), specializations: z.array(z.string()).openapi({ - description: - "The ID(s) of specialization(s) associated with this major; if any are present, one is mandatory for this major.", + description: "The ID(s) of specialization(s) associated with this major", example: [ "BS-201A", "BS-201B", diff --git a/apps/api/src/services/programs.ts b/apps/api/src/services/programs.ts index 3aaa40e0..99af3e14 100644 --- a/apps/api/src/services/programs.ts +++ b/apps/api/src/services/programs.ts @@ -9,12 +9,14 @@ import type { ugradRequirementsQuerySchema, } from "$schema"; import type { database } from "@packages/db"; -import { eq, sql } from "@packages/db/drizzle"; +import { and, eq, sql } from "@packages/db/drizzle"; import { catalogProgram, collegeRequirement, degree, major, + majorRequirement, + majorSpecializationToRequirement, minor, sampleProgramVariation, schoolRequirement, @@ -102,32 +104,48 @@ export class ProgramsService { programType: "specialization"; query: z.infer; }) { + if (programType === "major") { + const [got] = await this.db + .select({ + id: major.id, + name: major.name, + requirements: majorRequirement.requirements, + schoolRequirements: { + name: collegeRequirement.name, + requirements: collegeRequirement.requirements, + }, + }) + .from(major) + .where( + and( + eq(major.id, query.programId), + query.specializationId + ? eq(majorSpecializationToRequirement.specId, query.specializationId) + : undefined, + ), + ) + .leftJoin(collegeRequirement, eq(major.collegeRequirement, collegeRequirement.id)) + .leftJoin( + majorSpecializationToRequirement, + eq(major.id, majorSpecializationToRequirement.majorId), + ) + .leftJoin( + majorRequirement, + eq(majorSpecializationToRequirement.requirementId, majorRequirement.id), + ) + .limit(1); + return orNull(got); + } + const table = { - major, minor, specialization, }[programType]; - - const [got] = await (programType !== "major" - ? this.db - .select({ id: table.id, name: table.name, requirements: table.requirements }) - .from(table) - : this.db - .select({ - id: major.id, - name: major.name, - requirements: major.requirements, - schoolRequirements: { - name: collegeRequirement.name, - requirements: collegeRequirement.requirements, - }, - }) - .from(major) - .leftJoin(collegeRequirement, eq(major.collegeRequirement, collegeRequirement.id)) - ) + const [got] = await this.db + .select({ id: table.id, name: table.name, requirements: table.requirements }) + .from(table) .where(eq(table.id, query.programId)) .limit(1); - return orNull(got); } diff --git a/apps/data-pipeline/degreeworks-scraper/src/components/DegreeworksClient.ts b/apps/data-pipeline/degreeworks-scraper/src/components/DegreeworksClient.ts index 8b52ae25..69d7dbe0 100644 --- a/apps/data-pipeline/degreeworks-scraper/src/components/DegreeworksClient.ts +++ b/apps/data-pipeline/degreeworks-scraper/src/components/DegreeworksClient.ts @@ -97,12 +97,14 @@ export class DegreeworksClient { * @param degree a degree code, e.g. "BS" * @param school this corresponds to the UCI notion of division, e.g. "U" or "G" * @param majorCode a major code + * @param specCode a specialization code * @param college this corresponds to the UCI notion of school, e.g. 55 for the school of bio sci */ async getMajorAudit( degree: string, school: string, majorCode: string, + specCode?: string, college?: string, ): Promise< | { @@ -122,6 +124,7 @@ export class DegreeworksClient { goals: [ { code: "MAJOR", value: majorCode }, ...(college ? [{ code: "COLLEGE", value: college }] : []), + ...(specCode ? [{ code: "SPEC", value: specCode }] : []), ], }), headers: this.headers, diff --git a/apps/data-pipeline/degreeworks-scraper/src/components/Scraper.ts b/apps/data-pipeline/degreeworks-scraper/src/components/Scraper.ts index 619a0b68..e9dcbd59 100644 --- a/apps/data-pipeline/degreeworks-scraper/src/components/Scraper.ts +++ b/apps/data-pipeline/degreeworks-scraper/src/components/Scraper.ts @@ -20,8 +20,14 @@ import { const JWT_HEADER_PREFIX_LENGTH = 7; -// (school code, major code, degree code) -type ProgramTriplet = [string, string, string]; +type ProgramCodes = { + schoolCode: string; + degreeCode: string; + majorCode: string; + specCode?: string; +}; +// 'majorName;specCode'. If no specialization is taken, simply 'majorName' +type MajorSpecId = string | `${string};${string}`; export class Scraper { private ap!: AuditParser; @@ -36,8 +42,7 @@ export class Scraper { private done = false; private parsedUgradRequirements = new Map(); private parsedMinorPrograms = new Map(); - // both undergrad majors and grad programs; tuple of (school, program) - private parsedPrograms = new Map(); + private parsedPrograms = new Map(); // (parent major, name, program object) private parsedSpecializations = new Map< string, @@ -56,6 +61,10 @@ export class Scraper { ); } + private asMajorSpecId(majorName: string, specCode?: string): MajorSpecId { + return specCode ? `${majorName};${specCode}` : majorName; + } + private findDwNameFor( awardTypesMap: Map>, catalogueDegree: z.infer, @@ -81,7 +90,7 @@ export class Scraper { * * However, we operate under the assumption that every valid triplet is among the ones returned by this method. * @private */ - private async discoverValidDegrees(): Promise { + private async discoverValidDegrees(): Promise { const [awardTypes, reports] = await Promise.all([ fetch("https://www.reg.uci.edu/mdsd/api/lookups/awardTypes").then((r) => r.json()), fetch("https://www.reg.uci.edu/mdsd/api/reports", { @@ -129,8 +138,15 @@ export class Scraper { ) .flatMap((ent) => { const withMatchedDegree = this.findDwNameFor(awardTypesMap, ent) - .map((dwName) => [ent.school.schoolCode, ent.major.majorCode, dwName]) - .toArray() as ProgramTriplet[]; + .map( + (dwName) => + ({ + schoolCode: ent.school.schoolCode, + majorCode: ent.major.majorCode, + degreeCode: dwName, + }) as ProgramCodes, + ) + .toArray(); if (withMatchedDegree.length === 0) { console.log( @@ -142,46 +158,45 @@ export class Scraper { }); } - private async scrapePrograms(degrees: Iterable) { - const ret = new Map(); - for (const [schoolCode, majorCode, degreeCode] of degrees) { + private async scrapePrograms(degrees: Iterable) { + const ret = new Map(); + for (const { schoolCode, majorCode, degreeCode, specCode } of degrees) { const audit = await this.dw.getMajorAudit( degreeCode, // bachelor's degrees probably get an abbreviation starting with B degreeCode.startsWith("B") ? "U" : "G", majorCode, + specCode, schoolCode, ); - const majorAudit = audit?.major; + const specLogInfo = specCode ? ` specCode = ${specCode}` : ""; + const majorLogInfo = `(majorCode = ${majorCode}, degree = ${degreeCode}${specLogInfo})`; + if (!majorAudit) { - console.log( - `Requirements block not found (majorCode = ${majorCode}, degree = ${degreeCode})`, - ); + console.log(`Requirements block not found ${majorLogInfo}`); continue; } - - if (ret.has(majorAudit.title)) { - console.log( - `Requirements block already exists for "${majorAudit.title}" (majorCode = ${majorCode}, degree = ${degreeCode})`, - ); + if (ret.has(this.asMajorSpecId(majorAudit.title, specCode))) { + console.log(`Requirements block already exists for "${majorAudit.title}" ${majorLogInfo}`); continue; } - - ret.set(majorAudit.title, [ - audit?.college + ret.set(this.asMajorSpecId(majorAudit.title, specCode), { + school: audit?.college ? await this.ap.parseBlock( `${schoolCode}-COLLEGE-${majorCode}-${degreeCode}`, audit?.college, ) : undefined, - await this.ap.parseBlock(`${schoolCode}-MAJOR-${majorCode}-${degreeCode}`, majorAudit), - ]); + major: await this.ap.parseBlock( + `${schoolCode}-MAJOR-${majorCode}-${degreeCode}`, + majorAudit, + ), + specCode, + }); - console.log( - `Requirements block found and parsed for "${majorAudit.title}" (majorCode = ${majorCode}, degree = ${degreeCode})`, - ); + console.log(`Requirements block found and parsed for "${majorAudit.title}" ${majorLogInfo}`); } return ret; } @@ -196,8 +211,8 @@ export class Scraper { // as of this commit, this spec is seemingly valid with any major but that's not really true if (specCode === "OACSC") { // "optional american chemical society certification" - const inMap = this.parsedPrograms.get("Major in Chemistry") as MajorProgram; - return inMap ? [inMap[1]] : []; + const inMap = this.parsedPrograms.get(this.asMajorSpecId("Major in Chemistry")); + return inMap ? [inMap.major] : []; } // there seems to be a soft convention that specializations are their major code followed by uppercase letters @@ -209,8 +224,8 @@ export class Scraper { const [, maybeMajorCode] = asSuffixedMajorCode; return this.parsedPrograms .entries() - .filter(([_k, [_school, major]]) => major.code === maybeMajorCode) - .map(([_k, [_school, major]]) => major) + .filter(([_k, { major }]) => major.code === maybeMajorCode) + .map(([_k, { major }]) => major) .toArray(); } @@ -305,6 +320,7 @@ export class Scraper { console.log(`loading ${this.specializationCache.size} cached specializations`); this.knownSpecializations = await this.dw.getMapping("specializations"); + const foundMajorSpecPairs: ProgramCodes[] = []; for (const [specCode, specName] of this.knownSpecializations.entries()) { let specBlock: Block | undefined; @@ -318,9 +334,9 @@ export class Scraper { if (got !== null) { specBlock = got.block; - const majorProgram = this.parsedPrograms.get(got.parent.name); + const majorProgram = this.parsedPrograms.get(this.asMajorSpecId(got.parent.name)); if (majorProgram) { - foundMajor = majorProgram[1]; + foundMajor = majorProgram.major; } else { console.log( `warning: ${specName} has cached relation to non-existent major, ${got.parent.name} (spec code = ${specCode})`, @@ -363,6 +379,13 @@ export class Scraper { foundMajorAssured.specs.push(specCode); + foundMajorSpecPairs.push({ + schoolCode: foundMajorAssured.degreeType?.startsWith("B") ? "U" : "G", + degreeCode: foundMajorAssured.degreeType, + majorCode: foundMajorAssured.code, + specCode, + } as ProgramCodes); + this.specializationCache.set(specCode, { parent: foundMajorAssured, block: specBlock, @@ -399,9 +422,13 @@ export class Scraper { } } + for (const [majorSpecId, majorProgram] of await this.scrapePrograms(foundMajorSpecPairs)) { + this.parsedPrograms.set(majorSpecId, majorProgram); + } + // After we match specializations to a major // we ensure that majors with 0 specs don't require a specialization - for (const [, [, major]] of this.parsedPrograms) { + for (const [, { major }] of this.parsedPrograms) { if (major.specs.length === 0) { major.specializationRequired = false; } @@ -409,10 +436,9 @@ export class Scraper { this.degreesAwarded = new Map( Array.from( - new Set(this.parsedPrograms.entries().map(([, [_s, program]]) => program.degreeType ?? "")), + new Set(this.parsedPrograms.entries().map(([, { major }]) => major.degreeType ?? "")), ).map((x): [string, string] => [x, this.degrees?.get(x) ?? ""]), ); - // Post-processing steps. // As of this commit, the only program which seems to require both of @@ -420,16 +446,18 @@ export class Scraper { // cleaner way to address this, but this is such an insanely niche case // that it's probably not worth the effort to write a general solution. - const x = this.parsedPrograms.get("Major in Art History"); + const x = this.parsedPrograms.get(this.asMajorSpecId("Major in Art History")); const y = this.parsedSpecializations.get("AHGEO")?.[2]; const z = this.parsedSpecializations.get("AHPER")?.[2]; if (x && y && z) { - x[1].specs = []; - x[1].specializationRequired = false; - x[1].requirements = [...x[1].requirements, ...y.requirements, ...z.requirements]; + x.major.specs = []; + x.major.specializationRequired = false; + x.major.requirements = [...x.major.requirements, ...y.requirements, ...z.requirements]; this.parsedSpecializations.delete("AHGEO"); this.parsedSpecializations.delete("AHPER"); - this.parsedPrograms.set("Major in Art History", x); + this.parsedPrograms.delete(this.asMajorSpecId("Major in Art History", "AHPER")); + this.parsedPrograms.delete(this.asMajorSpecId("Major in Art History", "AHGEO")); + this.parsedPrograms.set(this.asMajorSpecId("Major in Art History"), x); } this.done = true; diff --git a/apps/data-pipeline/degreeworks-scraper/src/index.ts b/apps/data-pipeline/degreeworks-scraper/src/index.ts index 0f2929aa..dcb83665 100644 --- a/apps/data-pipeline/degreeworks-scraper/src/index.ts +++ b/apps/data-pipeline/degreeworks-scraper/src/index.ts @@ -6,6 +6,8 @@ import { collegeRequirement, degree, major, + majorRequirement, + majorSpecializationToRequirement, minor, schoolRequirement, specialization, @@ -44,41 +46,76 @@ async function main() { .toArray(); const collegeBlocks = [] as (typeof collegeRequirement.$inferInsert)[]; - const majorData = parsedPrograms + + const majorSpecData = parsedPrograms .values() - .map(([college, { name, degreeType, code, requirements, specializationRequired }]) => { - let collegeBlockIndex: number | undefined; - if (college?.requirements) { - const wouldInsert = { name: college.name, requirements: college.requirements }; - const existing = collegeBlocks.findIndex((schoolExisting) => { - try { - assert.deepStrictEqual(schoolExisting, wouldInsert); - return true; - } catch { - return false; - } - }); + .map( + ({ + school: college, + major: { name, degreeType, code, requirements, specializationRequired }, + specCode, + }) => { + let collegeBlockIndex: number | undefined; + if (college?.requirements) { + const wouldInsert = { name: college.name, requirements: college.requirements }; + const existing = collegeBlocks.findIndex((schoolExisting) => { + try { + assert.deepStrictEqual(schoolExisting, wouldInsert); + return true; + } catch { + return false; + } + }); - if (existing === -1) { - collegeBlocks.push(wouldInsert); - collegeBlockIndex = collegeBlocks.length - 1; - } else { - collegeBlockIndex = existing; + if (existing === -1) { + collegeBlocks.push(wouldInsert); + collegeBlockIndex = collegeBlocks.length - 1; + } else { + collegeBlockIndex = existing; + } } - } - return { - id: `${degreeType}-${code}`, - degreeId: degreeType ?? "", - code, - name, - specializationRequired, - requirements, - ...(collegeBlockIndex !== undefined ? { collegeBlockIndex } : {}), - }; - }) + return { + id: `${degreeType}-${code}`, + degreeId: degreeType ?? "", + code, + ...(specCode !== undefined ? { specId: `${degreeType}-${specCode}` } : {}), + name, + specializationRequired, + requirements, + ...(collegeBlockIndex !== undefined ? { collegeBlockIndex } : {}), + }; + }, + ) .toArray(); + const majorRequirementBlocks = [] as (typeof majorRequirement.$inferInsert)[]; + const majorSpecToRequirementData = majorSpecData.map(({ id, specId, requirements }) => { + const wouldInsert = { requirements }; + let majorRequirementBlockIndex: number | undefined = undefined; + const existing = majorRequirementBlocks.findIndex((req) => { + try { + assert.deepEqual(wouldInsert, req); + return true; + } catch { + return false; + } + }); + if (existing === -1) { + majorRequirementBlocks.push(wouldInsert); + majorRequirementBlockIndex = majorRequirementBlocks.length - 1; + } else { + majorRequirementBlockIndex = existing; + } + return { + majorId: id, + specId, + majorRequirementBlockIndex, + }; + }); + + const majorData = majorSpecData.filter(({ specId }) => specId === undefined); + const minorData = parsedMinorPrograms .values() .map(({ name, code: id, requirements }) => ({ id, name, requirements })) @@ -93,6 +130,7 @@ async function main() { requirements, })) .toArray(); + await db.transaction(async (tx) => { if (ucRequirementData && geRequirementData) { await tx @@ -159,6 +197,16 @@ async function main() { .returning({ id: collegeRequirement.id }) .then((rows) => rows.map(({ id }) => id)); + const majorRequirementBlockIds = await tx + .insert(majorRequirement) + .values(majorRequirementBlocks) + .onConflictDoUpdate({ + target: majorRequirement.id, + set: conflictUpdateSetAllCols(majorRequirement), + }) + .returning({ id: majorRequirement.id }) + .then((rows) => rows.map(({ id }) => id)); + for (const majorObj of majorData) { if (majorObj.collegeBlockIndex !== undefined) { (majorObj as typeof major.$inferInsert).collegeRequirement = @@ -166,6 +214,12 @@ async function main() { } } + for (const majorSpecObj of majorSpecToRequirementData) { + if (majorSpecObj.majorRequirementBlockIndex !== undefined) { + (majorSpecObj as typeof majorSpecializationToRequirement.$inferInsert).requirementId = + majorRequirementBlockIds[majorSpecObj.majorRequirementBlockIndex]; + } + } await tx .insert(major) .values(majorData) @@ -173,11 +227,22 @@ async function main() { await tx .insert(minor) .values(minorData) - .onConflictDoUpdate({ target: major.id, set: conflictUpdateSetAllCols(minor) }); + .onConflictDoUpdate({ target: minor.id, set: conflictUpdateSetAllCols(minor) }); await tx .insert(specialization) .values(specData) - .onConflictDoUpdate({ target: major.id, set: conflictUpdateSetAllCols(specialization) }); + .onConflictDoUpdate({ + target: specialization.id, + set: conflictUpdateSetAllCols(specialization), + }); + + await tx + .insert(majorSpecializationToRequirement) + .values(majorSpecToRequirementData) + .onConflictDoUpdate({ + target: majorSpecializationToRequirement.id, + set: conflictUpdateSetAllCols(majorSpecializationToRequirement), + }); }); exit(0); } diff --git a/packages/db/migrations/0027_polymorphic_major_requirements.sql b/packages/db/migrations/0027_polymorphic_major_requirements.sql new file mode 100644 index 00000000..ae32b86e --- /dev/null +++ b/packages/db/migrations/0027_polymorphic_major_requirements.sql @@ -0,0 +1,35 @@ +CREATE TABLE IF NOT EXISTS "major_requirement" ( + "requirements" jsonb NOT NULL, + "id" bigint PRIMARY KEY GENERATED ALWAYS AS (jsonb_hash_extended(requirements, 0)) STORED NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "major_specialization_to_requirement" ( + "id" varchar PRIMARY KEY GENERATED ALWAYS AS ( + CASE WHEN "major_specialization_to_requirement"."spec_id" IS NOT NULL + THEN "major_specialization_to_requirement"."major_id" || '+' || "major_specialization_to_requirement"."spec_id" + ELSE "major_specialization_to_requirement"."major_id" + END) STORED NOT NULL, + "major_id" varchar NOT NULL, + "spec_id" varchar, + "requirement_id" bigint +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "major_specialization_to_requirement" ADD CONSTRAINT "major_specialization_to_requirement_major_id_major_id_fk" FOREIGN KEY ("major_id") REFERENCES "public"."major"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "major_specialization_to_requirement" ADD CONSTRAINT "major_specialization_to_requirement_spec_id_specialization_id_fk" FOREIGN KEY ("spec_id") REFERENCES "public"."specialization"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "major_specialization_to_requirement" ADD CONSTRAINT "major_specialization_to_requirement_requirement_id_major_requirement_id_fk" FOREIGN KEY ("requirement_id") REFERENCES "public"."major_requirement"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +ALTER TABLE "major" DROP COLUMN IF EXISTS "requirements"; \ No newline at end of file diff --git a/packages/db/migrations/meta/0027_snapshot.json b/packages/db/migrations/meta/0027_snapshot.json new file mode 100644 index 00000000..6632c722 --- /dev/null +++ b/packages/db/migrations/meta/0027_snapshot.json @@ -0,0 +1,4641 @@ +{ + "id": "ccc196dc-0591-4a1d-ab1d-968b95b909e7", + "prevId": "c0f62b68-af2c-4377-bf84-83a14454c844", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.ap_exam": { + "name": "ap_exam", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "catalogue_name": { + "name": "catalogue_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ap_exam_reward": { + "name": "ap_exam_reward", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "units_granted": { + "name": "units_granted", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "elective_units_granted": { + "name": "elective_units_granted", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "ge_1a_courses_granted": { + "name": "ge_1a_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_1b_courses_granted": { + "name": "ge_1b_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_2_courses_granted": { + "name": "ge_2_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_3_courses_granted": { + "name": "ge_3_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_4_courses_granted": { + "name": "ge_4_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_5a_courses_granted": { + "name": "ge_5a_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_5b_courses_granted": { + "name": "ge_5b_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_6_courses_granted": { + "name": "ge_6_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_7_courses_granted": { + "name": "ge_7_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "ge_8_courses_granted": { + "name": "ge_8_courses_granted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "courses_granted": { + "name": "courses_granted", + "type": "json", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ap_exam_to_reward": { + "name": "ap_exam_to_reward", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "exam_id": { + "name": "exam_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "reward": { + "name": "reward", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "ap_exam_to_reward_exam_id_score_index": { + "name": "ap_exam_to_reward_exam_id_score_index", + "columns": [ + { + "expression": "exam_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "score", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "ap_exam_to_reward_exam_id_ap_exam_id_fk": { + "name": "ap_exam_to_reward_exam_id_ap_exam_id_fk", + "tableFrom": "ap_exam_to_reward", + "tableTo": "ap_exam", + "columnsFrom": ["exam_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "ap_exam_to_reward_reward_ap_exam_reward_id_fk": { + "name": "ap_exam_to_reward_reward_ap_exam_reward_id_fk", + "tableFrom": "ap_exam_to_reward", + "tableTo": "ap_exam_reward", + "columnsFrom": ["reward"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.calendar_term": { + "name": "calendar_term", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true, + "generated": { + "as": "\"calendar_term\".\"year\" || ' ' || CASE WHEN \"calendar_term\".\"quarter\" = 'Fall' THEN 'Fall' WHEN \"calendar_term\".\"quarter\" = 'Winter' THEN 'Winter' WHEN \"calendar_term\".\"quarter\" = 'Spring' THEN 'Spring' WHEN \"calendar_term\".\"quarter\" = 'Summer1' THEN 'Summer1' WHEN \"calendar_term\".\"quarter\" = 'Summer10wk' THEN 'Summer10wk' WHEN \"calendar_term\".\"quarter\" = 'Summer2' THEN 'Summer2' ELSE '' END", + "type": "stored" + } + }, + "year": { + "name": "year", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "quarter": { + "name": "quarter", + "type": "term", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "instruction_start": { + "name": "instruction_start", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "instruction_end": { + "name": "instruction_end", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "finals_start": { + "name": "finals_start", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "finals_end": { + "name": "finals_end", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "soc_available": { + "name": "soc_available", + "type": "date", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.catalogue_program": { + "name": "catalogue_program", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "program_name": { + "name": "program_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.college_requirement": { + "name": "college_requirement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "requirements": { + "name": "requirements", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "requirements_hash": { + "name": "requirements_hash", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "jsonb_hash_extended(requirements, 0)", + "type": "stored" + } + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "college_requirement_requirements_hash_unique": { + "name": "college_requirement_requirements_hash_unique", + "nullsNotDistinct": false, + "columns": ["requirements_hash"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.course": { + "name": "course", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "department": { + "name": "department", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "shortened_dept": { + "name": "shortened_dept", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "generated": { + "as": "REPLACE(\"course\".\"department\", ' ', '')", + "type": "stored" + } + }, + "department_alias": { + "name": "department_alias", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "course_number": { + "name": "course_number", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "course_numeric": { + "name": "course_numeric", + "type": "integer", + "primaryKey": false, + "notNull": true, + "generated": { + "as": "CASE REGEXP_REPLACE(\"course\".\"course_number\", '\\D', '', 'g') WHEN '' THEN 0 ELSE REGEXP_REPLACE(\"course\".\"course_number\", '\\D', '', 'g')::INTEGER END", + "type": "stored" + } + }, + "school": { + "name": "school", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "course_level": { + "name": "course_level", + "type": "course_level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "min_units": { + "name": "min_units", + "type": "numeric(4, 2)", + "primaryKey": false, + "notNull": true + }, + "max_units": { + "name": "max_units", + "type": "numeric(4, 2)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "department_name": { + "name": "department_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "prerequisite_tree": { + "name": "prerequisite_tree", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "prerequisite_text": { + "name": "prerequisite_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "repeatability": { + "name": "repeatability", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "grading_option": { + "name": "grading_option", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "concurrent": { + "name": "concurrent", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "same_as": { + "name": "same_as", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "restriction": { + "name": "restriction", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "overlap": { + "name": "overlap", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "corequisites": { + "name": "corequisites", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_ge_1a": { + "name": "is_ge_1a", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_1b": { + "name": "is_ge_1b", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_2": { + "name": "is_ge_2", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_3": { + "name": "is_ge_3", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_4": { + "name": "is_ge_4", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_5a": { + "name": "is_ge_5a", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_5b": { + "name": "is_ge_5b", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_6": { + "name": "is_ge_6", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_7": { + "name": "is_ge_7", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_8": { + "name": "is_ge_8", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "ge_text": { + "name": "ge_text", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "course_search_index": { + "name": "course_search_index", + "columns": [ + { + "expression": "(\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"id\", '')), 'A') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"department\", '')), 'B') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"department_alias\", '')), 'B') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"shortened_dept\", '')), 'B') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"course_number\", '')), 'B') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"course_numeric\"::TEXT, '')), 'B') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"title\", '')), 'C') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"description\", '')), 'D')\n)", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "shortened_dept": { + "name": "shortened_dept", + "columns": [ + { + "expression": "shortened_dept", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.degree": { + "name": "degree", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "division": { + "name": "division", + "type": "division", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dining_diet_restriction": { + "name": "dining_diet_restriction", + "schema": "", + "columns": { + "dish_id": { + "name": "dish_id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "contains_eggs": { + "name": "contains_eggs", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "contains_fish": { + "name": "contains_fish", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "contains_milk": { + "name": "contains_milk", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "contains_peanuts": { + "name": "contains_peanuts", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "contains_sesame": { + "name": "contains_sesame", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "contains_shellfish": { + "name": "contains_shellfish", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "contains_soy": { + "name": "contains_soy", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "contains_tree_nuts": { + "name": "contains_tree_nuts", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "contains_wheat": { + "name": "contains_wheat", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_gluten_free": { + "name": "is_gluten_free", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_halal": { + "name": "is_halal", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_kosher": { + "name": "is_kosher", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_locally_grown": { + "name": "is_locally_grown", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_organic": { + "name": "is_organic", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_vegan": { + "name": "is_vegan", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_vegetarian": { + "name": "is_vegetarian", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "dining_diet_restriction_dish_id_dining_dish_id_fk": { + "name": "dining_diet_restriction_dish_id_dining_dish_id_fk", + "tableFrom": "dining_diet_restriction", + "tableTo": "dining_dish", + "columnsFrom": ["dish_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dining_dish": { + "name": "dining_dish", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "station_id": { + "name": "station_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "ingredients": { + "name": "ingredients", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "image_url": { + "name": "image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "dining_dish_station_id_index": { + "name": "dining_dish_station_id_index", + "columns": [ + { + "expression": "station_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "dining_dish_station_id_dining_station_id_fk": { + "name": "dining_dish_station_id_dining_station_id_fk", + "tableFrom": "dining_dish", + "tableTo": "dining_station", + "columnsFrom": ["station_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dining_dish_to_period": { + "name": "dining_dish_to_period", + "schema": "", + "columns": { + "period_id": { + "name": "period_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "dish_id": { + "name": "dish_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "dining_dish_to_period_period_id_dining_period_id_fk": { + "name": "dining_dish_to_period_period_id_dining_period_id_fk", + "tableFrom": "dining_dish_to_period", + "tableTo": "dining_period", + "columnsFrom": ["period_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "dining_dish_to_period_dish_id_dining_dish_id_fk": { + "name": "dining_dish_to_period_dish_id_dining_dish_id_fk", + "tableFrom": "dining_dish_to_period", + "tableTo": "dining_dish", + "columnsFrom": ["dish_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dining_event": { + "name": "dining_event", + "schema": "", + "columns": { + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "restaurant_id": { + "name": "restaurant_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end": { + "name": "end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "dining_event_restaurant_id_dining_restaurant_id_fk": { + "name": "dining_event_restaurant_id_dining_restaurant_id_fk", + "tableFrom": "dining_event", + "tableTo": "dining_restaurant", + "columnsFrom": ["restaurant_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "dining_event_pk": { + "name": "dining_event_pk", + "columns": ["title", "restaurant_id", "start"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dining_nutrition_info": { + "name": "dining_nutrition_info", + "schema": "", + "columns": { + "dish_id": { + "name": "dish_id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "serving_size": { + "name": "serving_size", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "serving_unit": { + "name": "serving_unit", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "calories": { + "name": "calories", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "total_fat_g": { + "name": "total_fat_g", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "trans_fat_g": { + "name": "trans_fat_g", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "saturated_fat_g": { + "name": "saturated_fat_g", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "cholesterol_mg": { + "name": "cholesterol_mg", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "sodium_mg": { + "name": "sodium_mg", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "total_carbs_g": { + "name": "total_carbs_g", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "dietary_fiber_g": { + "name": "dietary_fiber_g", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "sugars_g": { + "name": "sugars_g", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "protein_g": { + "name": "protein_g", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "calcium": { + "name": "calcium", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "iron": { + "name": "iron", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "vitamin_a": { + "name": "vitamin_a", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "vitamin_c": { + "name": "vitamin_c", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "dining_nutrition_info_dish_id_dining_dish_id_fk": { + "name": "dining_nutrition_info_dish_id_dining_dish_id_fk", + "tableFrom": "dining_nutrition_info", + "tableTo": "dining_dish", + "columnsFrom": ["dish_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dining_period": { + "name": "dining_period", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "adobe_id": { + "name": "adobe_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "restaurant_id": { + "name": "restaurant_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "start_time": { + "name": "start_time", + "type": "time", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "time", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "dining_period_adobe_id_date_restaurant_id_index": { + "name": "dining_period_adobe_id_date_restaurant_id_index", + "columns": [ + { + "expression": "adobe_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "restaurant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "dining_period_date_index": { + "name": "dining_period_date_index", + "columns": [ + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "dining_period_restaurant_id_index": { + "name": "dining_period_restaurant_id_index", + "columns": [ + { + "expression": "restaurant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "dining_period_restaurant_id_dining_restaurant_id_fk": { + "name": "dining_period_restaurant_id_dining_restaurant_id_fk", + "tableFrom": "dining_period", + "tableTo": "dining_restaurant", + "columnsFrom": ["restaurant_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dining_restaurant": { + "name": "dining_restaurant", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dining_station": { + "name": "dining_station", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "restaurant_id": { + "name": "restaurant_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "dining_station_restaurant_id_index": { + "name": "dining_station_restaurant_id_index", + "columns": [ + { + "expression": "restaurant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "dining_station_restaurant_id_dining_restaurant_id_fk": { + "name": "dining_station_restaurant_id_dining_restaurant_id_fk", + "tableFrom": "dining_station", + "tableTo": "dining_restaurant", + "columnsFrom": ["restaurant_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.instructor": { + "name": "instructor", + "schema": "", + "columns": { + "ucinetid": { + "name": "ucinetid", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "department": { + "name": "department", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "instructor_search_index": { + "name": "instructor_search_index", + "columns": [ + { + "expression": "(\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"ucinetid\", '')), 'A') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"name\", '')), 'B') ||\n SETWEIGHT(TO_TSVECTOR('english', COALESCE(\"title\", '')), 'B')\n)", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.instructor_to_websoc_instructor": { + "name": "instructor_to_websoc_instructor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "instructor_ucinetid": { + "name": "instructor_ucinetid", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "websoc_instructor_name": { + "name": "websoc_instructor_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "instructor_to_websoc_instructor_instructor_ucinetid_index": { + "name": "instructor_to_websoc_instructor_instructor_ucinetid_index", + "columns": [ + { + "expression": "instructor_ucinetid", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "instructor_to_websoc_instructor_websoc_instructor_name_index": { + "name": "instructor_to_websoc_instructor_websoc_instructor_name_index", + "columns": [ + { + "expression": "websoc_instructor_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "instructor_to_websoc_instructor_instructor_ucinetid_websoc_instructor_name_index": { + "name": "instructor_to_websoc_instructor_instructor_ucinetid_websoc_instructor_name_index", + "columns": [ + { + "expression": "instructor_ucinetid", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "websoc_instructor_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "instructor_to_websoc_instructor_instructor_ucinetid_instructor_ucinetid_fk": { + "name": "instructor_to_websoc_instructor_instructor_ucinetid_instructor_ucinetid_fk", + "tableFrom": "instructor_to_websoc_instructor", + "tableTo": "instructor", + "columnsFrom": ["instructor_ucinetid"], + "columnsTo": ["ucinetid"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "instructor_to_websoc_instructor_websoc_instructor_name_websoc_instructor_name_fk": { + "name": "instructor_to_websoc_instructor_websoc_instructor_name_websoc_instructor_name_fk", + "tableFrom": "instructor_to_websoc_instructor", + "tableTo": "websoc_instructor", + "columnsFrom": ["websoc_instructor_name"], + "columnsTo": ["name"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.larc_section": { + "name": "larc_section", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "course_id": { + "name": "course_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "days_string": { + "name": "days_string", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "time_string": { + "name": "time_string", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "start_time": { + "name": "start_time", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "instructor": { + "name": "instructor", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "building": { + "name": "building", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "meets_monday": { + "name": "meets_monday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_tuesday": { + "name": "meets_tuesday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_wednesday": { + "name": "meets_wednesday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_thursday": { + "name": "meets_thursday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_friday": { + "name": "meets_friday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_saturday": { + "name": "meets_saturday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_sunday": { + "name": "meets_sunday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "larc_section_course_id_index": { + "name": "larc_section_course_id_index", + "columns": [ + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "larc_section_course_id_websoc_course_id_fk": { + "name": "larc_section_course_id_websoc_course_id_fk", + "tableFrom": "larc_section", + "tableTo": "websoc_course", + "columnsFrom": ["course_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.library_traffic": { + "name": "library_traffic", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true + }, + "library_name": { + "name": "library_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "location_name": { + "name": "location_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "traffic_count": { + "name": "traffic_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "traffic_percentage": { + "name": "traffic_percentage", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "library_traffic_library_name_index": { + "name": "library_traffic_library_name_index", + "columns": [ + { + "expression": "library_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "library_traffic_location_name_index": { + "name": "library_traffic_location_name_index", + "columns": [ + { + "expression": "location_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.library_traffic_history": { + "name": "library_traffic_history", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "location_id": { + "name": "location_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "traffic_count": { + "name": "traffic_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "traffic_percentage": { + "name": "traffic_percentage", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "library_traffic_history_location_id_timestamp_index": { + "name": "library_traffic_history_location_id_timestamp_index", + "columns": [ + { + "expression": "location_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "timestamp", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "library_traffic_history_location_id_library_traffic_id_fk": { + "name": "library_traffic_history_location_id_library_traffic_id_fk", + "tableFrom": "library_traffic_history", + "tableTo": "library_traffic", + "columnsFrom": ["location_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.major": { + "name": "major", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "degree_id": { + "name": "degree_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "specialization_required": { + "name": "specialization_required", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "college_requirement": { + "name": "college_requirement", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "major_degree_id_index": { + "name": "major_degree_id_index", + "columns": [ + { + "expression": "degree_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "major_college_requirement_index": { + "name": "major_college_requirement_index", + "columns": [ + { + "expression": "college_requirement", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "major_degree_id_degree_id_fk": { + "name": "major_degree_id_degree_id_fk", + "tableFrom": "major", + "tableTo": "degree", + "columnsFrom": ["degree_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "major_college_requirement_college_requirement_id_fk": { + "name": "major_college_requirement_college_requirement_id_fk", + "tableFrom": "major", + "tableTo": "college_requirement", + "columnsFrom": ["college_requirement"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.major_requirement": { + "name": "major_requirement", + "schema": "", + "columns": { + "requirements": { + "name": "requirements", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "bigint", + "primaryKey": true, + "notNull": true, + "generated": { + "as": "jsonb_hash_extended(requirements, 0)", + "type": "stored" + } + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.major_specialization_to_requirement": { + "name": "major_specialization_to_requirement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true, + "generated": { + "as": "\n CASE WHEN \"major_specialization_to_requirement\".\"spec_id\" IS NOT NULL\n THEN \"major_specialization_to_requirement\".\"major_id\" || '+' || \"major_specialization_to_requirement\".\"spec_id\"\n ELSE \"major_specialization_to_requirement\".\"major_id\"\n END", + "type": "stored" + } + }, + "major_id": { + "name": "major_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "spec_id": { + "name": "spec_id", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "requirement_id": { + "name": "requirement_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "major_specialization_to_requirement_major_id_major_id_fk": { + "name": "major_specialization_to_requirement_major_id_major_id_fk", + "tableFrom": "major_specialization_to_requirement", + "tableTo": "major", + "columnsFrom": ["major_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "major_specialization_to_requirement_spec_id_specialization_id_fk": { + "name": "major_specialization_to_requirement_spec_id_specialization_id_fk", + "tableFrom": "major_specialization_to_requirement", + "tableTo": "specialization", + "columnsFrom": ["spec_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "major_specialization_to_requirement_requirement_id_major_requirement_id_fk": { + "name": "major_specialization_to_requirement_requirement_id_major_requirement_id_fk", + "tableFrom": "major_specialization_to_requirement", + "tableTo": "major_requirement", + "columnsFrom": ["requirement_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.minor": { + "name": "minor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "requirements": { + "name": "requirements", + "type": "json", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.prerequisite": { + "name": "prerequisite", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "dep_dept": { + "name": "dep_dept", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "prerequisite_id": { + "name": "prerequisite_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "dependency_id": { + "name": "dependency_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "prerequisite_dep_dept_index": { + "name": "prerequisite_dep_dept_index", + "columns": [ + { + "expression": "dep_dept", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "prerequisite_prerequisite_id_index": { + "name": "prerequisite_prerequisite_id_index", + "columns": [ + { + "expression": "prerequisite_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "prerequisite_dependency_id_index": { + "name": "prerequisite_dependency_id_index", + "columns": [ + { + "expression": "dependency_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "prerequisite_prerequisite_id_dependency_id_index": { + "name": "prerequisite_prerequisite_id_dependency_id_index", + "columns": [ + { + "expression": "prerequisite_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "dependency_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sample_program_variation": { + "name": "sample_program_variation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "program_id": { + "name": "program_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "sample_program": { + "name": "sample_program", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "variation_notes": { + "name": "variation_notes", + "type": "varchar[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::VARCHAR[]" + } + }, + "indexes": {}, + "foreignKeys": { + "sample_program_variation_program_id_catalogue_program_id_fk": { + "name": "sample_program_variation_program_id_catalogue_program_id_fk", + "tableFrom": "sample_program_variation", + "tableTo": "catalogue_program", + "columnsFrom": ["program_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.school_requirement": { + "name": "school_requirement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "requirements": { + "name": "requirements", + "type": "json", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.specialization": { + "name": "specialization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "major_id": { + "name": "major_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "requirements": { + "name": "requirements", + "type": "json", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "specialization_major_id_index": { + "name": "specialization_major_id_index", + "columns": [ + { + "expression": "major_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "specialization_major_id_major_id_fk": { + "name": "specialization_major_id_major_id_fk", + "tableFrom": "specialization", + "tableTo": "major", + "columnsFrom": ["major_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.study_location": { + "name": "study_location", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.study_room": { + "name": "study_room", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "location": { + "name": "location", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "directions": { + "name": "directions", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "tech_enhanced": { + "name": "tech_enhanced", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "study_location_id": { + "name": "study_location_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "study_room_study_location_id_index": { + "name": "study_room_study_location_id_index", + "columns": [ + { + "expression": "study_location_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "study_room_study_location_id_study_location_id_fk": { + "name": "study_room_study_location_id_study_location_id_fk", + "tableFrom": "study_room", + "tableTo": "study_location", + "columnsFrom": ["study_location_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.study_room_slot": { + "name": "study_room_slot", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "study_room_id": { + "name": "study_room_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "start": { + "name": "start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end": { + "name": "end", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "is_available": { + "name": "is_available", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "study_room_slot_study_room_id_index": { + "name": "study_room_slot_study_room_id_index", + "columns": [ + { + "expression": "study_room_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "study_room_slot_study_room_id_start_end_index": { + "name": "study_room_slot_study_room_id_start_end_index", + "columns": [ + { + "expression": "study_room_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "start", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "end", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "study_room_slot_study_room_id_study_room_id_fk": { + "name": "study_room_slot_study_room_id_study_room_id_fk", + "tableFrom": "study_room_slot", + "tableTo": "study_room", + "columnsFrom": ["study_room_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_course": { + "name": "websoc_course", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "department_id": { + "name": "department_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "course_id": { + "name": "course_id", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "generated": { + "as": "REPLACE(\"websoc_course\".\"dept_code\", ' ', '') || \"websoc_course\".\"course_number\"", + "type": "stored" + } + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "year": { + "name": "year", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "quarter": { + "name": "quarter", + "type": "term", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "school_name": { + "name": "school_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "dept_code": { + "name": "dept_code", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "course_title": { + "name": "course_title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "course_number": { + "name": "course_number", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "course_numeric": { + "name": "course_numeric", + "type": "integer", + "primaryKey": false, + "notNull": true, + "generated": { + "as": "CASE REGEXP_REPLACE(\"websoc_course\".\"course_number\", '\\D', '', 'g') WHEN '' THEN 0 ELSE REGEXP_REPLACE(\"websoc_course\".\"course_number\", '\\D', '', 'g')::INTEGER END", + "type": "stored" + } + }, + "course_comment": { + "name": "course_comment", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prerequisite_link": { + "name": "prerequisite_link", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "is_ge_1a": { + "name": "is_ge_1a", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_1b": { + "name": "is_ge_1b", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_2": { + "name": "is_ge_2", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_3": { + "name": "is_ge_3", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_4": { + "name": "is_ge_4", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_5a": { + "name": "is_ge_5a", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_5b": { + "name": "is_ge_5b", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_6": { + "name": "is_ge_6", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_7": { + "name": "is_ge_7", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_ge_8": { + "name": "is_ge_8", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "websoc_course_department_id_index": { + "name": "websoc_course_department_id_index", + "columns": [ + { + "expression": "department_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_course_id_index": { + "name": "websoc_course_course_id_index", + "columns": [ + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_school_name_dept_code_course_number_course_title_index": { + "name": "websoc_course_year_quarter_school_name_dept_code_course_number_course_title_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "school_name", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "dept_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "course_number", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "course_title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_1a_index": { + "name": "websoc_course_year_quarter_is_ge_1a_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_1a", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_1b_index": { + "name": "websoc_course_year_quarter_is_ge_1b_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_1b", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_2_index": { + "name": "websoc_course_year_quarter_is_ge_2_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_3_index": { + "name": "websoc_course_year_quarter_is_ge_3_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_4_index": { + "name": "websoc_course_year_quarter_is_ge_4_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_5a_index": { + "name": "websoc_course_year_quarter_is_ge_5a_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_5a", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_5b_index": { + "name": "websoc_course_year_quarter_is_ge_5b_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_5b", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_6_index": { + "name": "websoc_course_year_quarter_is_ge_6_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_6", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_7_index": { + "name": "websoc_course_year_quarter_is_ge_7_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_7", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_is_ge_8_index": { + "name": "websoc_course_year_quarter_is_ge_8_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_ge_8", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_dept_code_index": { + "name": "websoc_course_year_quarter_dept_code_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "dept_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_course_year_quarter_dept_code_course_number_index": { + "name": "websoc_course_year_quarter_dept_code_course_number_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "dept_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "course_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "websoc_course_department_id_websoc_department_id_fk": { + "name": "websoc_course_department_id_websoc_department_id_fk", + "tableFrom": "websoc_course", + "tableTo": "websoc_department", + "columnsFrom": ["department_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_department": { + "name": "websoc_department", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "school_id": { + "name": "school_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "year": { + "name": "year", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "quarter": { + "name": "quarter", + "type": "term", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "dept_code": { + "name": "dept_code", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "dept_name": { + "name": "dept_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "dept_comment": { + "name": "dept_comment", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "section_code_range_comments": { + "name": "section_code_range_comments", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "course_number_range_comments": { + "name": "course_number_range_comments", + "type": "text[]", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "websoc_department_school_id_index": { + "name": "websoc_department_school_id_index", + "columns": [ + { + "expression": "school_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_department_year_quarter_school_id_dept_code_index": { + "name": "websoc_department_year_quarter_school_id_dept_code_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "school_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "dept_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "websoc_department_school_id_websoc_school_id_fk": { + "name": "websoc_department_school_id_websoc_school_id_fk", + "tableFrom": "websoc_department", + "tableTo": "websoc_school", + "columnsFrom": ["school_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_instructor": { + "name": "websoc_instructor", + "schema": "", + "columns": { + "name": { + "name": "name", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_location": { + "name": "websoc_location", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "building": { + "name": "building", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "room": { + "name": "room", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "websoc_location_building_room_index": { + "name": "websoc_location_building_room_index", + "columns": [ + { + "expression": "building", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "room", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_meta": { + "name": "websoc_meta", + "schema": "", + "columns": { + "name": { + "name": "name", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "last_scraped": { + "name": "last_scraped", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "last_dept_scraped": { + "name": "last_dept_scraped", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_school": { + "name": "websoc_school", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "year": { + "name": "year", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "quarter": { + "name": "quarter", + "type": "term", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "school_name": { + "name": "school_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "school_comment": { + "name": "school_comment", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "websoc_school_year_quarter_school_name_index": { + "name": "websoc_school_year_quarter_school_name_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "school_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_section": { + "name": "websoc_section", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "course_id": { + "name": "course_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "year": { + "name": "year", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "quarter": { + "name": "quarter", + "type": "term", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "units": { + "name": "units", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "websoc_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "instructors": { + "name": "instructors", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "meetings": { + "name": "meetings", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "final_exam_string": { + "name": "final_exam_string", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "final_exam": { + "name": "final_exam", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "section_num": { + "name": "section_num", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "max_capacity": { + "name": "max_capacity", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "section_code": { + "name": "section_code", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "section_type": { + "name": "section_type", + "type": "websoc_section_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "num_requested": { + "name": "num_requested", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "restriction_string": { + "name": "restriction_string", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "restriction_a": { + "name": "restriction_a", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_b": { + "name": "restriction_b", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_c": { + "name": "restriction_c", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_d": { + "name": "restriction_d", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_e": { + "name": "restriction_e", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_f": { + "name": "restriction_f", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_g": { + "name": "restriction_g", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_h": { + "name": "restriction_h", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_i": { + "name": "restriction_i", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_j": { + "name": "restriction_j", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_k": { + "name": "restriction_k", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_l": { + "name": "restriction_l", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_m": { + "name": "restriction_m", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_n": { + "name": "restriction_n", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_o": { + "name": "restriction_o", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_r": { + "name": "restriction_r", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_s": { + "name": "restriction_s", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "restriction_x": { + "name": "restriction_x", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "num_on_waitlist": { + "name": "num_on_waitlist", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_waitlist_cap": { + "name": "num_waitlist_cap", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "section_comment": { + "name": "section_comment", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "num_new_only_reserved": { + "name": "num_new_only_reserved", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_currently_total_enrolled": { + "name": "num_currently_total_enrolled", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_currently_section_enrolled": { + "name": "num_currently_section_enrolled", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_cancelled": { + "name": "is_cancelled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "generated": { + "as": "\"websoc_section\".\"section_comment\" LIKE '%*** CANCELLED ***%' OR \"websoc_section\".\"section_comment\" LIKE '%*** CANCELED ***%'", + "type": "stored" + } + }, + "web_url": { + "name": "web_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": { + "websoc_section_course_id_index": { + "name": "websoc_section_course_id_index", + "columns": [ + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_section_year_quarter_section_code_index": { + "name": "websoc_section_year_quarter_section_code_index", + "columns": [ + { + "expression": "year", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "quarter", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "section_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "websoc_section_course_id_websoc_course_id_fk": { + "name": "websoc_section_course_id_websoc_course_id_fk", + "tableFrom": "websoc_section", + "tableTo": "websoc_course", + "columnsFrom": ["course_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_section_enrollment": { + "name": "websoc_section_enrollment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "section_id": { + "name": "section_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "date", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "year": { + "name": "year", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "quarter": { + "name": "quarter", + "type": "term", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "max_capacity": { + "name": "max_capacity", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "num_currently_total_enrolled": { + "name": "num_currently_total_enrolled", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_on_waitlist": { + "name": "num_on_waitlist", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_waitlist_cap": { + "name": "num_waitlist_cap", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_requested": { + "name": "num_requested", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_new_only_reserved": { + "name": "num_new_only_reserved", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "websoc_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "websoc_section_enrollment_section_id_index": { + "name": "websoc_section_enrollment_section_id_index", + "columns": [ + { + "expression": "section_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_section_enrollment_section_id_created_at_index": { + "name": "websoc_section_enrollment_section_id_created_at_index", + "columns": [ + { + "expression": "section_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "websoc_section_enrollment_section_id_websoc_section_id_fk": { + "name": "websoc_section_enrollment_section_id_websoc_section_id_fk", + "tableFrom": "websoc_section_enrollment", + "tableTo": "websoc_section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_section_grade": { + "name": "websoc_section_grade", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "section_id": { + "name": "section_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "grade_a_count": { + "name": "grade_a_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "grade_b_count": { + "name": "grade_b_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "grade_c_count": { + "name": "grade_c_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "grade_d_count": { + "name": "grade_d_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "grade_f_count": { + "name": "grade_f_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "grade_p_count": { + "name": "grade_p_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "grade_np_count": { + "name": "grade_np_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "grade_w_count": { + "name": "grade_w_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "average_gpa": { + "name": "average_gpa", + "type": "numeric(3, 2)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "websoc_section_grade_section_id_index": { + "name": "websoc_section_grade_section_id_index", + "columns": [ + { + "expression": "section_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "websoc_section_grade_section_id_websoc_section_id_fk": { + "name": "websoc_section_grade_section_id_websoc_section_id_fk", + "tableFrom": "websoc_section_grade", + "tableTo": "websoc_section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "websoc_section_grade_section_id_unique": { + "name": "websoc_section_grade_section_id_unique", + "nullsNotDistinct": false, + "columns": ["section_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_section_meeting": { + "name": "websoc_section_meeting", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "section_id": { + "name": "section_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "section_code": { + "name": "section_code", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "meeting_index": { + "name": "meeting_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "time_string": { + "name": "time_string", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "time_is_tba": { + "name": "time_is_tba", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "generated": { + "as": "\"websoc_section_meeting\".\"time_string\" LIKE '%TBA%'", + "type": "stored" + } + }, + "start_time": { + "name": "start_time", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_time": { + "name": "end_time", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "days_string": { + "name": "days_string", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "meets_monday": { + "name": "meets_monday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_tuesday": { + "name": "meets_tuesday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_wednesday": { + "name": "meets_wednesday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_thursday": { + "name": "meets_thursday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_friday": { + "name": "meets_friday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_saturday": { + "name": "meets_saturday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "meets_sunday": { + "name": "meets_sunday", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "websoc_section_meeting_section_id_index": { + "name": "websoc_section_meeting_section_id_index", + "columns": [ + { + "expression": "section_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "websoc_section_meeting_section_id_websoc_section_id_fk": { + "name": "websoc_section_meeting_section_id_websoc_section_id_fk", + "tableFrom": "websoc_section_meeting", + "tableTo": "websoc_section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_section_meeting_to_location": { + "name": "websoc_section_meeting_to_location", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "meeting_id": { + "name": "meeting_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "location_id": { + "name": "location_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "websoc_section_meeting_to_location_meeting_id_index": { + "name": "websoc_section_meeting_to_location_meeting_id_index", + "columns": [ + { + "expression": "meeting_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_section_meeting_to_location_location_id_index": { + "name": "websoc_section_meeting_to_location_location_id_index", + "columns": [ + { + "expression": "location_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_section_meeting_to_location_meeting_id_location_id_index": { + "name": "websoc_section_meeting_to_location_meeting_id_location_id_index", + "columns": [ + { + "expression": "meeting_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "location_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "websoc_section_meeting_to_location_meeting_id_websoc_section_meeting_id_fk": { + "name": "websoc_section_meeting_to_location_meeting_id_websoc_section_meeting_id_fk", + "tableFrom": "websoc_section_meeting_to_location", + "tableTo": "websoc_section_meeting", + "columnsFrom": ["meeting_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "websoc_section_meeting_to_location_location_id_websoc_location_id_fk": { + "name": "websoc_section_meeting_to_location_location_id_websoc_location_id_fk", + "tableFrom": "websoc_section_meeting_to_location", + "tableTo": "websoc_location", + "columnsFrom": ["location_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.websoc_section_to_instructor": { + "name": "websoc_section_to_instructor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "section_id": { + "name": "section_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "instructor_name": { + "name": "instructor_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "websoc_section_to_instructor_section_id_index": { + "name": "websoc_section_to_instructor_section_id_index", + "columns": [ + { + "expression": "section_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "websoc_section_to_instructor_instructor_name_index": { + "name": "websoc_section_to_instructor_instructor_name_index", + "columns": [ + { + "expression": "instructor_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "websoc_section_to_instructor_section_id_websoc_section_id_fk": { + "name": "websoc_section_to_instructor_section_id_websoc_section_id_fk", + "tableFrom": "websoc_section_to_instructor", + "tableTo": "websoc_section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "websoc_section_to_instructor_instructor_name_websoc_instructor_name_fk": { + "name": "websoc_section_to_instructor_instructor_name_websoc_instructor_name_fk", + "tableFrom": "websoc_section_to_instructor", + "tableTo": "websoc_instructor", + "columnsFrom": ["instructor_name"], + "columnsTo": ["name"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.course_level": { + "name": "course_level", + "schema": "public", + "values": ["LowerDiv", "UpperDiv", "Graduate"] + }, + "public.division": { + "name": "division", + "schema": "public", + "values": ["Undergraduate", "Graduate"] + }, + "public.term": { + "name": "term", + "schema": "public", + "values": ["Fall", "Winter", "Spring", "Summer1", "Summer10wk", "Summer2"] + }, + "public.websoc_section_type": { + "name": "websoc_section_type", + "schema": "public", + "values": [ + "Act", + "Col", + "Dis", + "Fld", + "Lab", + "Lec", + "Qiz", + "Res", + "Sem", + "Stu", + "Tap", + "Tut" + ] + }, + "public.websoc_status": { + "name": "websoc_status", + "schema": "public", + "values": ["OPEN", "Waitl", "FULL", "NewOnly"] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": { + "public.course_view": { + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "department": { + "name": "department", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "shortened_dept": { + "name": "shortened_dept", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "generated": { + "as": "REPLACE(\"course\".\"department\", ' ', '')", + "type": "stored" + } + }, + "department_alias": { + "name": "department_alias", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "course_number": { + "name": "course_number", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "course_numeric": { + "name": "course_numeric", + "type": "integer", + "primaryKey": false, + "notNull": true, + "generated": { + "as": "CASE REGEXP_REPLACE(\"course\".\"course_number\", '\\D', '', 'g') WHEN '' THEN 0 ELSE REGEXP_REPLACE(\"course\".\"course_number\", '\\D', '', 'g')::INTEGER END", + "type": "stored" + } + }, + "school": { + "name": "school", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "course_level": { + "name": "course_level", + "type": "course_level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "min_units": { + "name": "min_units", + "type": "numeric(4, 2)", + "primaryKey": false, + "notNull": true + }, + "max_units": { + "name": "max_units", + "type": "numeric(4, 2)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "department_name": { + "name": "department_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "prerequisite_tree": { + "name": "prerequisite_tree", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "prerequisite_text": { + "name": "prerequisite_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "repeatability": { + "name": "repeatability", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "grading_option": { + "name": "grading_option", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "concurrent": { + "name": "concurrent", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "same_as": { + "name": "same_as", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "restriction": { + "name": "restriction", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "overlap": { + "name": "overlap", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "corequisites": { + "name": "corequisites", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_ge_1a": { + "name": "is_ge_1a", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_1b": { + "name": "is_ge_1b", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_2": { + "name": "is_ge_2", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_3": { + "name": "is_ge_3", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_4": { + "name": "is_ge_4", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_5a": { + "name": "is_ge_5a", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_5b": { + "name": "is_ge_5b", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_6": { + "name": "is_ge_6", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_7": { + "name": "is_ge_7", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_ge_8": { + "name": "is_ge_8", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "ge_text": { + "name": "ge_text", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "definition": "select \"course\".\"id\", \"course\".\"updated_at\", \"course\".\"department\", \"course\".\"shortened_dept\", \"course\".\"department_alias\", \"course\".\"course_number\", \"course\".\"course_numeric\", \"course\".\"school\", \"course\".\"title\", \"course\".\"course_level\", \"course\".\"min_units\", \"course\".\"max_units\", \"course\".\"description\", \"course\".\"department_name\", \"course\".\"prerequisite_tree\", \"course\".\"prerequisite_text\", \"course\".\"repeatability\", \"course\".\"grading_option\", \"course\".\"concurrent\", \"course\".\"same_as\", \"course\".\"restriction\", \"course\".\"overlap\", \"course\".\"corequisites\", \"course\".\"is_ge_1a\", \"course\".\"is_ge_1b\", \"course\".\"is_ge_2\", \"course\".\"is_ge_3\", \"course\".\"is_ge_4\", \"course\".\"is_ge_5a\", \"course\".\"is_ge_5b\", \"course\".\"is_ge_6\", \"course\".\"is_ge_7\", \"course\".\"is_ge_8\", \"course\".\"ge_text\", \n ARRAY_REMOVE(COALESCE(\n (\n SELECT ARRAY_AGG(\n CASE WHEN \"prerequisite_course\".\"id\" IS NULL THEN NULL\n ELSE JSONB_BUILD_OBJECT(\n 'id', \"prerequisite_course\".\"id\",\n 'title', \"prerequisite_course\".\"title\",\n 'department', \"prerequisite_course\".\"department\",\n 'courseNumber', \"prerequisite_course\".\"course_number\"\n )\n END\n )\n FROM \"prerequisite\"\n LEFT JOIN \"course\" \"prerequisite_course\" ON \"prerequisite_course\".\"id\" = \"prerequisite\".\"prerequisite_id\"\n WHERE \"prerequisite\".\"dependency_id\" = \"course\".\"id\"\n ),\n ARRAY[]::JSONB[]), NULL)\n as \"prerequisites\", \n ARRAY_REMOVE(COALESCE(\n (\n SELECT ARRAY_AGG(\n CASE WHEN \"dependency_course\".\"id\" IS NULL THEN NULL\n ELSE JSONB_BUILD_OBJECT(\n 'id', \"dependency_course\".\"id\",\n 'title', \"dependency_course\".\"title\",\n 'department', \"dependency_course\".\"department\",\n 'courseNumber', \"dependency_course\".\"course_number\"\n )\n END\n )\n FROM \"prerequisite\" \"dependency\"\n LEFT JOIN \"course\" \"dependency_course\" ON \"dependency_course\".\"id\" = \"dependency\".\"dependency_id\"\n WHERE \"dependency\".\"prerequisite_id\" = \"course\".\"id\"\n ),\n ARRAY[]::JSONB[]), NULL)\n as \"dependencies\", \n ARRAY_REMOVE(ARRAY_AGG(DISTINCT\n CASE WHEN \"websoc_course\".\"year\" IS NULL THEN NULL\n ELSE CONCAT(\"websoc_course\".\"year\", ' ', \"websoc_course\".\"quarter\")\n END\n ), NULL)\n as \"terms\", \n ARRAY_REMOVE(COALESCE(ARRAY_AGG(DISTINCT\n CASE WHEN \"instructor\".\"ucinetid\" IS NULL THEN NULL\n ELSE JSONB_BUILD_OBJECT(\n 'ucinetid', \"instructor\".\"ucinetid\",\n 'name', \"instructor\".\"name\",\n 'title', \"instructor\".\"title\",\n 'email', \"instructor\".\"email\",\n 'department', \"instructor\".\"department\",\n 'shortenedNames', ARRAY(\n SELECT \"instructor_to_websoc_instructor\".\"websoc_instructor_name\"\n FROM \"instructor_to_websoc_instructor\"\n WHERE \"instructor_to_websoc_instructor\".\"instructor_ucinetid\" = \"instructor\".\"ucinetid\"\n )\n )\n END\n ), ARRAY[]::JSONB[]), NULL)\n as \"instructors\" from \"course\" left join \"websoc_course\" on \"websoc_course\".\"course_id\" = \"course\".\"id\" left join \"websoc_section\" on \"websoc_section\".\"course_id\" = \"websoc_course\".\"id\" left join \"websoc_section_to_instructor\" on \"websoc_section_to_instructor\".\"section_id\" = \"websoc_section\".\"id\" left join \"websoc_instructor\" on \"websoc_instructor\".\"name\" = \"websoc_section_to_instructor\".\"instructor_name\" left join \"instructor_to_websoc_instructor\" on \"instructor_to_websoc_instructor\".\"websoc_instructor_name\" = \"websoc_instructor\".\"name\" left join \"instructor\" on (\"instructor\".\"ucinetid\" = \"instructor_to_websoc_instructor\".\"instructor_ucinetid\" and \"instructor\".\"ucinetid\" is not null and \"instructor\".\"ucinetid\" <> 'student') group by \"course\".\"id\"", + "name": "course_view", + "schema": "public", + "isExisting": false, + "materialized": true + }, + "public.instructor_view": { + "columns": { + "ucinetid": { + "name": "ucinetid", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "department": { + "name": "department", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "definition": "with \"shortened_names_cte\" as (select \"instructor_ucinetid\", ARRAY_AGG(\"websoc_instructor_name\") as \"shortened_names\" from \"instructor_to_websoc_instructor\" group by \"instructor_to_websoc_instructor\".\"instructor_ucinetid\"), \"courses_cte\" as (with \"terms_cte\" as (select \"course\".\"id\", \"instructor_to_websoc_instructor\".\"instructor_ucinetid\", \n ARRAY_REMOVE(ARRAY_AGG(DISTINCT\n CASE WHEN \"websoc_course\".\"year\" IS NULL THEN NULL\n ELSE CONCAT(\"websoc_course\".\"year\", ' ', \"websoc_course\".\"quarter\")\n END\n ), NULL) as \"terms\" from \"course\" left join \"websoc_course\" on \"websoc_course\".\"course_id\" = \"course\".\"id\" left join \"websoc_section\" on \"websoc_section\".\"course_id\" = \"websoc_course\".\"id\" left join \"websoc_section_to_instructor\" on \"websoc_section_to_instructor\".\"section_id\" = \"websoc_section\".\"id\" left join \"websoc_instructor\" on \"websoc_instructor\".\"name\" = \"websoc_section_to_instructor\".\"instructor_name\" left join \"instructor_to_websoc_instructor\" on \"instructor_to_websoc_instructor\".\"websoc_instructor_name\" = \"websoc_instructor\".\"name\" group by \"course\".\"id\", \"instructor_to_websoc_instructor\".\"instructor_ucinetid\") select \"terms_cte\".\"instructor_ucinetid\", \"course\".\"id\", \n CASE WHEN \"course\".\"id\" IS NULL\n THEN NULL\n ELSE JSONB_BUILD_OBJECT(\n 'id', \"course\".\"id\",\n 'title', \"course\".\"title\",\n 'department', \"course\".\"department\",\n 'courseNumber', \"course\".\"course_number\",\n 'terms', COALESCE(\"terms\", ARRAY[]::TEXT[])\n )\n END\n as \"course_info\" from \"course\" left join \"terms_cte\" on \"terms_cte\".\"id\" = \"course\".\"id\" group by \"course\".\"id\", \"terms_cte\".\"instructor_ucinetid\", \"terms\") select \"instructor\".\"ucinetid\", \"instructor\".\"name\", \"instructor\".\"title\", \"instructor\".\"email\", \"instructor\".\"department\", COALESCE(\"shortened_names\", ARRAY[]::TEXT[]) as \"shortened_names\", \n ARRAY_REMOVE(ARRAY_AGG(DISTINCT \"course_info\"), NULL)\n as \"courses\" from \"instructor\" left join \"shortened_names_cte\" on \"shortened_names_cte\".\"instructor_ucinetid\" = \"instructor\".\"ucinetid\" left join \"courses_cte\" on \"courses_cte\".\"instructor_ucinetid\" = \"instructor\".\"ucinetid\" where \"instructor\".\"ucinetid\" <> 'student' group by \"instructor\".\"ucinetid\", \"shortened_names\"", + "name": "instructor_view", + "schema": "public", + "isExisting": false, + "materialized": true + } + }, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 731a8542..1154fab3 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -190,6 +190,13 @@ "when": 1773306141597, "tag": "0026_requirements_id", "breakpoints": true + }, + { + "idx": 27, + "version": "7", + "when": 1773686494314, + "tag": "0027_polymorphic_major_requirements", + "breakpoints": true } ] } diff --git a/packages/db/src/schema.ts b/packages/db/src/schema.ts index 08344ff7..7dfb450b 100644 --- a/packages/db/src/schema.ts +++ b/packages/db/src/schema.ts @@ -103,10 +103,14 @@ export type DegreeWorksProgram = DegreeWorksProgramId & { }; /** - * (school, major) pair, because school requirements can vary by major + * Complete major requirements are the concatenation between school requirements that may vary by major and major requirements that may vary by specialization * eventually, we may want degree type; e.g. MFA provides some requirements */ -export type MajorProgram = [DegreeWorksProgram | undefined, DegreeWorksProgram]; +export type MajorProgram = { + school: DegreeWorksProgram | undefined; + major: DegreeWorksProgram; + specCode: string | undefined; +}; export type DegreeWorksCourseRequirement = { requirementType: "Course"; @@ -670,6 +674,34 @@ export const collegeRequirement = pgTable("college_requirement", { .unique(), }); +export const majorSpecializationToRequirement = pgTable("major_specialization_to_requirement", { + id: varchar("id") + .primaryKey() + .generatedAlwaysAs((): SQL => { + return sql` + CASE WHEN ${majorSpecializationToRequirement.specId} IS NOT NULL + THEN ${majorSpecializationToRequirement.majorId} || '+' || ${majorSpecializationToRequirement.specId} + ELSE ${majorSpecializationToRequirement.majorId} + END`; + }), + majorId: varchar("major_id") + .notNull() + .references(() => major.id), + specId: varchar("spec_id").references(() => specialization.id), + requirementId: bigint("requirement_id", { mode: "bigint" }).references(() => majorRequirement.id), +}); + +export const majorRequirement = pgTable( + "major_requirement", + { + requirements: jsonb("requirements").$type().notNull(), + id: bigint("id", { mode: "bigint" }) + .primaryKey() + .generatedAlwaysAs(sql`jsonb_hash_extended(requirements, 0)`), + }, + (table) => [], +); + export const major = pgTable( "major", { @@ -681,7 +713,6 @@ export const major = pgTable( name: varchar("name").notNull(), specializationRequired: boolean("specialization_required").notNull(), collegeRequirement: uuid("college_requirement").references(() => collegeRequirement.id), - requirements: json("requirements").$type().notNull(), }, (table) => [index().on(table.degreeId), index().on(table.collegeRequirement)], );