mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
[Updater] Add migration, update models
This commit is contained in:
committed by
Aaro Koivukangas
parent
b8e9d59217
commit
5bd7fb6792
@@ -21,15 +21,19 @@ import { EnrollmentModel } from './enrollment'
|
||||
import { OrganizationModel } from './organization'
|
||||
|
||||
@Table({
|
||||
underscored: false,
|
||||
underscored: true,
|
||||
modelName: 'course',
|
||||
tableName: 'course',
|
||||
})
|
||||
export class CourseModel extends Model implements Course {
|
||||
/* COLUMNS */
|
||||
@PrimaryKey
|
||||
@Column(DataType.STRING)
|
||||
declare id: Course['id']
|
||||
|
||||
@Column(DataType.STRING)
|
||||
declare groupId: Course['id']
|
||||
|
||||
@ForeignKey(() => CourseModel)
|
||||
@Column(DataType.STRING)
|
||||
declare code: Course['code']
|
||||
@@ -38,6 +42,39 @@ export class CourseModel extends Model implements Course {
|
||||
@Column(DataType.STRING)
|
||||
declare coursetypecode: Course['coursetypecode']
|
||||
|
||||
@Column(DataType.BOOLEAN)
|
||||
declare isStudyModule: Course['isStudyModule']
|
||||
|
||||
@Column(DataType.JSONB)
|
||||
declare name: Course['name']
|
||||
|
||||
@Column(DataType.DATE)
|
||||
declare maxAttainmentDate: Course['maxAttainmentDate']
|
||||
|
||||
@Column(DataType.DATE)
|
||||
declare minAttainmentDate: Course['minAttainmentDate']
|
||||
|
||||
@CreatedAt
|
||||
@Column({ field: 'created_at', type: DataType.DATE })
|
||||
declare createdAt: Course['createdAt']
|
||||
|
||||
@UpdatedAt
|
||||
@Column({ field: 'updated_at', type: DataType.DATE })
|
||||
declare updatedAt: Course['updatedAt']
|
||||
|
||||
@Column(DataType.JSONB)
|
||||
declare validityPeriod: Course['validityPeriod']
|
||||
|
||||
@Column(DataType.JSONB)
|
||||
declare substitutionGroups: Course['substitutionGroups']
|
||||
|
||||
@Column(DataType.BOOLEAN)
|
||||
declare isPrimary: Course['isPrimary']
|
||||
|
||||
@Column(DataType.STRING)
|
||||
declare courseUnitType: Course['courseUnitType']
|
||||
|
||||
/* RELATIONS */
|
||||
@BelongsTo(() => CourseTypeModel, { foreignKey: 'coursetypecode', targetKey: 'coursetypecode' })
|
||||
declare courseType: Course['courseType']
|
||||
|
||||
@@ -49,36 +86,4 @@ export class CourseModel extends Model implements Course {
|
||||
|
||||
@BelongsToMany(() => OrganizationModel, () => CourseProviderModel, 'coursecode')
|
||||
declare organizations: Course['organizations']
|
||||
|
||||
@Column(DataType.BOOLEAN)
|
||||
declare is_study_module: Course['is_study_module']
|
||||
|
||||
@Column(DataType.JSONB)
|
||||
declare name: Course['name']
|
||||
|
||||
@Column(DataType.DATE)
|
||||
declare max_attainment_date: Course['max_attainment_date']
|
||||
|
||||
@Column(DataType.DATE)
|
||||
declare min_attainment_date: Course['min_attainment_date']
|
||||
|
||||
@CreatedAt
|
||||
@Column({ field: 'created_at', type: DataType.DATE })
|
||||
declare createdAt: Course['createdAt']
|
||||
|
||||
@UpdatedAt
|
||||
@Column({ field: 'updated_at', type: DataType.DATE })
|
||||
declare updatedAt: Course['updatedAt']
|
||||
|
||||
@Column(DataType.JSONB)
|
||||
declare substitutions: Course['substitutions']
|
||||
|
||||
@Column(DataType.JSONB)
|
||||
declare substitution_groups: Course['substitution_groups']
|
||||
|
||||
@Column(DataType.STRING)
|
||||
declare course_unit_type: Course['course_unit_type']
|
||||
|
||||
@Column({ field: 'main_course_code', type: DataType.STRING })
|
||||
declare mainCourseCode: Course['mainCourseCode']
|
||||
}
|
||||
|
||||
@@ -6,21 +6,25 @@ import type { Enrollment } from './enrollment'
|
||||
import type { Organization } from './organization'
|
||||
|
||||
export type Course = {
|
||||
/* COLUMNS */
|
||||
id: string
|
||||
groupId: string
|
||||
code: string
|
||||
coursetypecode: string
|
||||
isStudyModule: boolean
|
||||
isPrimary: boolean
|
||||
name: Name
|
||||
maxAttainmentDate: Date | null
|
||||
minAttainmentDate: Date | null
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
substitutionGroups: string[][]
|
||||
validityPeriod: { startDate?: Date; endDate?: Date } | null
|
||||
courseUnitType: string
|
||||
|
||||
/* RELATIONS */
|
||||
courseType: CourseType
|
||||
credits: Credit[]
|
||||
enrollments: Enrollment[]
|
||||
organizations: Organization[]
|
||||
is_study_module: boolean
|
||||
name: Name
|
||||
max_attainment_date: Date
|
||||
min_attainment_date: Date
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
substitutions: string[]
|
||||
substitution_groups: string[][]
|
||||
course_unit_type: string
|
||||
mainCourseCode: string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
const { BOOLEAN, JSONB, STRING, TEXT } = require('sequelize')
|
||||
|
||||
/**
|
||||
* Add: groupId, validityPeriod, primary field
|
||||
* Remove: mainCourseCode, old substitutions
|
||||
* Additionally substitutionGroups now use the groupIds of course units, rather than the codes.
|
||||
*/
|
||||
module.exports = {
|
||||
up: async queryInterface => {
|
||||
await queryInterface.addColumn('course', 'group_id', STRING)
|
||||
await queryInterface.addColumn('course', 'validity_period', JSONB)
|
||||
await queryInterface.addColumn('course', 'is_primary', BOOLEAN)
|
||||
await queryInterface.removeColumn('course', 'main_course_code')
|
||||
await queryInterface.removeColumn('course', 'substitutions')
|
||||
},
|
||||
down: async queryInterface => {
|
||||
await queryInterface.removeColumn('course', 'group_id')
|
||||
await queryInterface.removeColumn('course', 'validity_period')
|
||||
await queryInterface.removeColumn('course', 'is_primary')
|
||||
await queryInterface.addColumn('course', 'main_course_code', TEXT)
|
||||
await queryInterface.addColumn('course', 'substitutions', JSONB)
|
||||
},
|
||||
}
|
||||
@@ -10,22 +10,28 @@ Course.init(
|
||||
type: STRING,
|
||||
primaryKey: true,
|
||||
},
|
||||
groupId: {
|
||||
type: STRING,
|
||||
},
|
||||
code: {
|
||||
type: STRING,
|
||||
},
|
||||
name: {
|
||||
type: JSONB,
|
||||
},
|
||||
is_study_module: {
|
||||
isStudyModule: {
|
||||
type: BOOLEAN,
|
||||
},
|
||||
isPrimary: {
|
||||
type: BOOLEAN,
|
||||
},
|
||||
coursetypecode: {
|
||||
type: STRING,
|
||||
},
|
||||
max_attainment_date: {
|
||||
maxAttainmentDate: {
|
||||
type: DATE,
|
||||
},
|
||||
min_attainment_date: {
|
||||
minAttainmentDate: {
|
||||
type: DATE,
|
||||
},
|
||||
createdAt: {
|
||||
@@ -36,22 +42,18 @@ Course.init(
|
||||
field: 'updated_at',
|
||||
type: DATE,
|
||||
},
|
||||
substitutions: {
|
||||
substitutionGroups: {
|
||||
type: JSONB,
|
||||
},
|
||||
substitution_groups: {
|
||||
validityPeriod: {
|
||||
type: JSONB,
|
||||
},
|
||||
course_unit_type: {
|
||||
type: STRING,
|
||||
},
|
||||
mainCourseCode: {
|
||||
field: 'main_course_code',
|
||||
courseUnitType: {
|
||||
type: STRING,
|
||||
},
|
||||
},
|
||||
{
|
||||
underscored: false,
|
||||
underscored: true,
|
||||
sequelize: dbConnections.sequelize,
|
||||
modelName: 'course',
|
||||
tableName: 'course',
|
||||
|
||||
@@ -236,14 +236,14 @@ export const courseProviderMapper =
|
||||
shares,
|
||||
})
|
||||
|
||||
export const courseMapper = courseIdToAttainments => (groupId, course, substitution_groups) => {
|
||||
export const courseMapper = courseIdToAttainments => (groupId, course, substitutionGroups, primaryId) => {
|
||||
const { id, code, name, study_level, course_unit_type, validity_period } = course
|
||||
|
||||
const courseAttainments = courseIdToAttainments[id] ?? []
|
||||
|
||||
// Attainments are sorted by attainment_date ASC
|
||||
const min_attainment_date = courseAttainments[0]?.attainment_date ?? null
|
||||
const max_attainment_date = courseAttainments[courseAttainments.length - 1]?.attainment_date ?? null
|
||||
const minAttainmentDate = courseAttainments[0]?.attainment_date ?? null
|
||||
const maxAttainmentDate = courseAttainments[courseAttainments.length - 1]?.attainment_date ?? null
|
||||
|
||||
return {
|
||||
id,
|
||||
@@ -251,12 +251,13 @@ export const courseMapper = courseIdToAttainments => (groupId, course, substitut
|
||||
name,
|
||||
code,
|
||||
coursetypecode: study_level,
|
||||
min_attainment_date,
|
||||
max_attainment_date,
|
||||
validity_period,
|
||||
is_study_module: !course_unit_type, // Only course units have a course_unit_type. If null -> must be a study module
|
||||
substitution_groups,
|
||||
course_unit_type,
|
||||
minAttainmentDate,
|
||||
maxAttainmentDate,
|
||||
validityPeriod: validity_period,
|
||||
isStudyModule: !course_unit_type, // Only course units have a course_unit_type. If null -> must be a study module
|
||||
isPrimary: primaryId === id,
|
||||
substitutionGroups,
|
||||
courseUnitType: course_unit_type,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,19 @@ const updateCourses = async (courseIdToAttainments, groupIdToCourse) => {
|
||||
const mapCourse = courseMapper(courseIdToAttainments)
|
||||
|
||||
for (const [groupId, courses] of Object.entries(groupIdToCourse)) {
|
||||
const now = new Date()
|
||||
const { id: primaryCourseId } = courses.reduce(
|
||||
(acc, cur) => {
|
||||
const start = new Date(cur.validity_period.startDate)
|
||||
if (start > acc.startDate && start < now) {
|
||||
acc.id = cur.id
|
||||
acc.startDate = start
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{ startDate: new Date(0), id: courses[0].id }
|
||||
)
|
||||
|
||||
for (const course of courses) {
|
||||
/** @type string[][] @description nested arrays of courseUnit groupIds. Modules have no substitutions. */
|
||||
const substitutionGroups = course.substitutions?.map(subGroup => subGroup.map(sub => sub.courseUnitGroupId)) ?? []
|
||||
@@ -55,7 +68,7 @@ const updateCourses = async (courseIdToAttainments, groupIdToCourse) => {
|
||||
const mapCourseProvider = courseProviderMapper(groupId)
|
||||
|
||||
courseProviders.push(...Object.values(organisationsById).map(mapCourseProvider))
|
||||
mappedCourses.push(mapCourse(groupId, course, substitutionGroups))
|
||||
mappedCourses.push(mapCourse(groupId, course, substitutionGroups, primaryCourseId))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user