diff --git a/apps/data-pipeline/websoc-scraper/package.json b/apps/data-pipeline/websoc-scraper/package.json index 5ecb3e0f..6c445a0f 100644 --- a/apps/data-pipeline/websoc-scraper/package.json +++ b/apps/data-pipeline/websoc-scraper/package.json @@ -14,6 +14,7 @@ "@icssc/libwebsoc-next": "1.1.1", "@packages/db": "workspace:*", "@packages/stdlib": "workspace:*", + "@types/node": "22.9.3", "cheerio": "1.0.0", "cross-fetch": "4.0.0" }, diff --git a/apps/data-pipeline/websoc-scraper/src/lib.ts b/apps/data-pipeline/websoc-scraper/src/lib.ts index 24d36768..f36b7d5d 100644 --- a/apps/data-pipeline/websoc-scraper/src/lib.ts +++ b/apps/data-pipeline/websoc-scraper/src/lib.ts @@ -14,7 +14,6 @@ import { and, asc, eq, gte, inArray, lte, sql } from "@packages/db/drizzle"; import type { WebsocSectionFinalExam } from "@packages/db/schema"; import { calendarTerm, - course, websocCourse, websocDepartment, websocInstructor, @@ -36,7 +35,6 @@ import { parseStartAndEndTimes, sleep, } from "@packages/stdlib"; -import { load } from "cheerio"; /** * WebSoc allows us to scrape up to 900 sections per chunk. @@ -48,7 +46,7 @@ const SECTIONS_PER_CHUNK = 891; * Section codes 98000-99999 are reserved for Study Abroad and Registrar testing. * These are not associated with any department that is searchable directly through WebSoc. */ -const LAST_SECTION_CODE = "97999"; +const LAST_SECTION_CODE = 97999; const geCategories = [ "GE-1A", @@ -78,44 +76,12 @@ const geCategoryToFlag: Record<(typeof geCategories)[number], keyof CourseGEUpda const geColumns = Object.values(geCategoryToFlag) as string[]; -export async function getDepts(db: ReturnType) { - const response = await fetch("https://www.reg.uci.edu/perl/WebSoc").then((x) => x.text()); - - const $ = load(response); - - const termsFromWebsoc = $("form") - .eq(1) - .find("select") - .eq(2) - .text() - .replace(/\t/g, "") - .replace(/ {4}/g, "") - .split("\n") - .map((x) => - x - .split(".") - .filter((y) => y !== " ") - .map((y) => y.trim()), - ) - .filter((x) => x[0].length) - .map((x) => (x.length === 1 ? "ALL" : x[0])) - .filter((x) => x !== "ALL"); - - const termsFromDb = await db - .select({ department: course.department }) - .from(course) - .then((rows) => Array.from(new Set(rows.map((row) => row.department)))); - - return Array.from(new Set(termsFromWebsoc.concat(termsFromDb))).toSorted(); -} - async function getTermsToScrape(db: ReturnType) { const now = new Date(); return db .select({ name: calendarTerm.id, lastScraped: websocMeta.lastScraped, - lastDeptScraped: websocMeta.lastDeptScraped, }) .from(calendarTerm) .leftJoin(websocMeta, eq(websocMeta.name, calendarTerm.id)) @@ -416,12 +382,7 @@ const courseUpdateSet = Object.fromEntries( Object.entries(allCourseCols).filter(([key]) => !geColumns.includes(key)), ); -const doChunkUpsert = async ( - db: ReturnType, - term: Term, - resp: WebsocResponse, - department: string | null, -) => +const doChunkUpsert = async (db: ReturnType, term: Term, resp: WebsocResponse) => await db.transaction(async (tx) => { const updatedAt = new Date(); const schools = await tx @@ -696,8 +657,10 @@ const doChunkUpsert = async ( }); const websocMetaValues = { name: termToName(term), + // update this on every scrape so that, even if we partially fail to scrape this term, + // the next scraping attempt will try another term first (if such another candidate term exists) + // before retrying this one lastScraped: updatedAt, - lastDeptScraped: department, }; await tx .insert(websocMeta) @@ -811,105 +774,72 @@ async function scrapeGEsForTerm(db: ReturnType, term: Term) { console.log(`Updated GE data for ${updates.size} courses`); } -export async function scrapeTerm( - db: ReturnType, - term: Term, - departments: string[], -) { +export async function scrapeTerm(db: ReturnType, term: Term) { const name = termToName(term); console.log(`Scraping term ${name}`); const sectionCodeBounds = await db - .execute( - sql>` + .execute<{ section_code: number }>( + sql<{ section_code: number }>` SELECT section_code FROM ( - SELECT LPAD(section_code::TEXT, 5, '0') AS section_code, + SELECT section_code, (ROW_NUMBER() OVER (ORDER BY section_code)) AS rownum FROM ${websocSection} WHERE ${websocSection.year} = ${term.year} AND ${websocSection.quarter} = ${term.quarter} ) - WHERE MOD(rownum, ${SECTIONS_PER_CHUNK}) = 0 OR MOD(rownum, ${SECTIONS_PER_CHUNK}) = 1; + WHERE MOD(rownum, ${SECTIONS_PER_CHUNK}) = 0; `, ) .then((xs) => xs.map((x) => x.section_code)); - if (departments.length) { - console.log(`Resuming scraping run at department ${departments[0]}.`); - for (const department of departments) { - console.log(`Scraping department ${department}`); - const resp = await request(term, { - department, - cancelledCourses: "Include", - }).then(normalizeResponse); - if (resp.schools.length) await doChunkUpsert(db, term, resp, department); - await sleep(1000); - } - } else if (!sectionCodeBounds.length) { - console.log("This term has never been scraped before. Falling back to department-wise scrape."); - for (const department of await getDepts(db)) { - console.log(`Scraping department ${department}`); - const resp = await request(term, { - department, - cancelledCourses: "Include", - }).then(normalizeResponse); - if (resp.schools.length) await doChunkUpsert(db, term, resp, department); - await sleep(1000); - } - } else { - console.log("Performing chunk-wise scrape."); - for (let i = 0; i < sectionCodeBounds.length; i += 2) { - const lower = sectionCodeBounds[i] as `${number}`; - const upper = (sectionCodeBounds[i + 1] ?? LAST_SECTION_CODE) as `${number}`; - await ingestChunk(db, term, lower, upper); - } + + console.log("Performing chunk-wise scrape."); + let lastKnownCode = 0; + for (const bound of sectionCodeBounds) { + await ingestChunk(db, term, lastKnownCode + 1, bound); + lastKnownCode = bound; } + + if (lastKnownCode < LAST_SECTION_CODE) { + await ingestChunk(db, term, lastKnownCode + 1, LAST_SECTION_CODE); + } + await scrapeGEsForTerm(db, term); - const lastScraped = new Date(); - const values = { name, lastScraped, lastDeptScraped: null }; - await db.transaction(async (tx) => { - await tx - .insert(websocMeta) - .values(values) - .onConflictDoUpdate({ target: websocMeta.name, set: values }); - }); + const values = { name, lastScraped: new Date() }; + await db + .insert(websocMeta) + .values(values) + .onConflictDoUpdate({ target: websocMeta.name, set: values }); } async function ingestChunk( db: ReturnType, term: Term, - lower: `${number}`, - upper: `${number}`, + lower: number, + upper: number, ) { - const sectionCodes = `${lower}-${upper}`; - console.log(`Scraping chunk ${sectionCodes}`); + const codeRangePretty = `${lower.toString().padStart(5, "0")}-${upper.toString().padStart(5, "0")}`; + console.log(`Scraping chunk ${codeRangePretty}`); try { const resp = await request(term, { - sectionCodes, + sectionCodes: codeRangePretty, cancelledCourses: "Include", }).then(normalizeResponse); - if (resp.schools.length) await doChunkUpsert(db, term, resp, null); + if (resp.schools.length) await doChunkUpsert(db, term, resp); await sleep(1000); } catch (e) { - /* - assuming network, etc. conditions are fine, we have more than 900 sections here - this means we somehow overran our 1% tolerance - that's okay; we can be suboptimal this time so we get all the sections that exist. - we're going to recompute the chunks at the start of the next scrape, - so that one will run optimally, given no such failure occurs again - - we're going to bisect this chunk and try the two halves separately; eventually, - we'll have <= 900 valid sections in a chunk and we'll be in the clear - */ - const lowerInt = Number.parseInt(lower, 10); - const upperInt = Number.parseInt(upper, 10); - const rangeLength = upperInt - lowerInt + 1; + // this isn't necessarily fatal; it's possible that we would have gotten more than 900 sections, which is disallowed + // let's just try again here; after the first scrape of this term, we'll get the code ranges right >95% of the time + const rangeLength = upper - lower + 1; if (rangeLength < 900) { // okay, no way this was a chunk overrun throw e; } - console.log(`Chunk ${sectionCodes} failed (probably too large); bisecting and trying again...`); + console.log( + `Chunk ${codeRangePretty} failed (probably too large); bisecting and trying again...`, + ); - const middleInt = lowerInt + Math.floor((upperInt - lowerInt) / 2); - await ingestChunk(db, term, lower, middleInt.toString().padStart(5, "0") as `${number}`); - await ingestChunk(db, term, (middleInt + 1).toString().padStart(5, "0") as `${number}`, upper); + const middle = lower + Math.floor((upper - lower) / 2); + await ingestChunk(db, term, lower, middle); + await ingestChunk(db, term, middle + 1, upper); } } @@ -917,15 +847,10 @@ export async function doScrape(db: ReturnType) { console.log("websoc-scraper starting"); const termsInDatabase = await getTermsToScrape(db); console.log(termsInDatabase); - const term = termsInDatabase.find((x) => x.lastDeptScraped !== null) ?? termsInDatabase[0]; + const term = termsInDatabase[0]; if (term?.name) { try { - const departments = await getDepts(db); - await scrapeTerm( - db, - nameToTerm(term.name), - term?.lastDeptScraped ? departments.slice(departments.indexOf(term.lastDeptScraped)) : [], - ); + await scrapeTerm(db, nameToTerm(term.name)); } catch (e) { console.error(e); } diff --git a/apps/data-pipeline/websoc-scraper/tsconfig.json b/apps/data-pipeline/websoc-scraper/tsconfig.json index 97d824e9..f63c58d1 100644 --- a/apps/data-pipeline/websoc-scraper/tsconfig.json +++ b/apps/data-pipeline/websoc-scraper/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../../tsconfig.json", "compilerOptions": { "baseUrl": ".", - "types": ["./worker-configuration.d.ts"], + "types": ["./worker-configuration.d.ts", "node"], "paths": { "$lib": ["./src/lib.ts"] } diff --git a/packages/db/migrations/0027_websoc_meta_drop_last_dept_scraped.sql b/packages/db/migrations/0027_websoc_meta_drop_last_dept_scraped.sql new file mode 100644 index 00000000..c650b67d --- /dev/null +++ b/packages/db/migrations/0027_websoc_meta_drop_last_dept_scraped.sql @@ -0,0 +1 @@ +ALTER TABLE "websoc_meta" DROP COLUMN IF EXISTS "last_dept_scraped"; \ 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..e63037b5 --- /dev/null +++ b/packages/db/migrations/meta/0027_snapshot.json @@ -0,0 +1,4543 @@ +{ + "id": "dc0f14bf-cd68-4558-a169-77a14cc5ff2a", + "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 + }, + "requirements": { + "name": "requirements", + "type": "json", + "primaryKey": false, + "notNull": true + } + }, + "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.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 + } + }, + "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..54fc1a63 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": 1773634820227, + "tag": "0027_websoc_meta_drop_last_dept_scraped", + "breakpoints": true } ] } diff --git a/packages/db/src/schema.ts b/packages/db/src/schema.ts index 08344ff7..2d0a32f8 100644 --- a/packages/db/src/schema.ts +++ b/packages/db/src/schema.ts @@ -224,7 +224,6 @@ export type SectionType = (typeof websocSectionTypes)[number]; export const websocMeta = pgTable("websoc_meta", { name: varchar("name").primaryKey(), lastScraped: timestamp("last_scraped", { mode: "date", withTimezone: true }).notNull(), - lastDeptScraped: varchar("last_dept_scraped"), }); export const websocSchool = pgTable( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 421c79ef..70c95b1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -378,6 +378,9 @@ importers: '@packages/stdlib': specifier: workspace:* version: link:../../../packages/stdlib + '@types/node': + specifier: 22.9.3 + version: 22.9.3 cheerio: specifier: 1.0.0 version: 1.0.0