#5645 - Institution profile updates - DB Migrations and Lookup data API#5691
#5645 - Institution profile updates - DB Migrations and Lookup data API#5691dheepak-aot merged 16 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds institution profile fields and introduces a system lookup configuration mechanism to store reference data like countries and provinces. The changes include database migrations, entity models, a new service layer for lookup management, and an API controller for accessing lookup data.
Changes:
- Added system lookup configuration table with countries and provinces reference data
- Extended institution table with new profile fields (country, province, classification, organization status, medical school status)
- Created service layer to load and cache lookup configurations in memory
- Added API controller endpoint to retrieve lookup entries by category
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| system-lookup-configuration.model.ts | New entity model for storing lookup data by category |
| system-lookup-category.type.ts | Enum defining lookup categories (Country, Province) |
| institution*.type.ts | Three new enums for institution classification, organization status, and medical school status |
| institution.model.ts | Added five nullable columns for institution profile information |
| Add-additional-information-cols.sql | Migration adds institution columns with validation constraints and backfills existing data |
| Create-system-lookup-configurations-table.sql | Creates lookup table with unique constraint on category+key |
| Insert-country-and-province-system-lookup.sql | Seeds 250+ countries and 13 Canadian provinces/territories |
| Create-function-is-valid-system-lookup-key.sql | PostgreSQL function to validate lookup keys via CHECK constraints |
| system-lookup-configuration.service.ts | Service to load and cache lookup configurations in memory |
| system-lookup-configuration.module.ts | Global module that loads lookups on application startup |
| system-lookup-configuration.controller.ts | Shared controller endpoint for all client types |
| system-lookup-configuration.dto.ts | Output DTOs for lookup entries |
| system-lookup-configuration.controller.getSystemLookupEntriesByCategory.e2e-spec.ts | E2E tests for the lookup endpoint |
| createFakeSystemLookupConfiguration | Test factory for creating fake lookup entries |
| create-institutions-and-authentication-users.ts | Updated test seeding to include new institution fields |
| */ | ||
| async onModuleInit(): Promise<void> { | ||
| this.logger.log("Loading system lookup configurations."); | ||
| await this.systemLookupConfigurationService.loadAllSystemLookupConfigurations(); |
There was a problem hiding this comment.
The service loads all system lookup configurations into memory on module initialization without any error handling. If the database query fails during startup, the application may start with an empty lookup map, potentially causing runtime errors. Consider adding error handling and logging for the initial load operation.
| await this.systemLookupConfigurationService.loadAllSystemLookupConfigurations(); | |
| try { | |
| await this.systemLookupConfigurationService.loadAllSystemLookupConfigurations(); | |
| this.logger.log("System lookup configurations loaded successfully."); | |
| } catch (error: unknown) { | |
| if (error instanceof Error) { | |
| this.logger.error( | |
| `Failed to load system lookup configurations during module initialization. ${error.message}`, | |
| error.stack, | |
| ); | |
| } else { | |
| this.logger.error( | |
| "Failed to load system lookup configurations during module initialization due to an unknown error.", | |
| ); | |
| } | |
| throw error; | |
| } |
There was a problem hiding this comment.
@dheepak-aot Are we not adding this suggested try-catch block?
There was a problem hiding this comment.
By adding the try-catch as described above, only possible benefit is custom error logging, does it justify the update?
...backend/libs/services/src/system-lookup-configuration/system-lookup-configuration.service.ts
Outdated
Show resolved
Hide resolved
.../src/route-controllers/system-lookup-configuration/models/system-lookup-configuration.dto.ts
Show resolved
Hide resolved
...backend/libs/services/src/system-lookup-configuration/system-lookup-configuration.service.ts
Show resolved
Hide resolved
.../backend/libs/services/src/system-lookup-configuration/system-lookup-configuration.module.ts
Show resolved
Hide resolved
| // TODO: These additional columns are currently nullable until all existing institutions | ||
| // have been backfilled with appropriate data. | ||
| // After that, these columns should not be nullable. |
There was a problem hiding this comment.
The comment incorrectly states these columns will be made non-nullable after backfilling, but the migration already includes an UPDATE statement that backfills existing institutions with values based on their institution type. The TODO comment should clarify whether additional manual backfilling is needed for edge cases not covered by the UPDATE statement, or if this TODO is obsolete.
| // TODO: These additional columns are currently nullable until all existing institutions | |
| // have been backfilled with appropriate data. | |
| // After that, these columns should not be nullable. | |
| // These additional columns are kept nullable in the entity to remain compatible | |
| // with existing data and the current database schema. Any change to make them | |
| // non-nullable must be done explicitly in a dedicated migration coordinated with | |
| // data backfilling and business requirements. |
...backend/libs/services/src/system-lookup-configuration/system-lookup-configuration.service.ts
Outdated
Show resolved
Hide resolved
.../src/route-controllers/system-lookup-configuration/models/system-lookup-configuration.dto.ts
Show resolved
Hide resolved
.../src/route-controllers/system-lookup-configuration/system-lookup-configuration.controller.ts
Show resolved
Hide resolved
...sts_/e2e/system-lookup-configuration.controller.getSystemLookupEntriesByCategory.e2e-spec.ts
Outdated
Show resolved
Hide resolved
| -- System user. | ||
| user_name = '8fb44f70-6ce6-11ed-b307-8743a2da47ef@system' | ||
| ) | ||
| WHERE |
There was a problem hiding this comment.
I do not understand the benefit of having the check between 1 and 7. IMO, it would be equivalent to check IF EXISTS, which we stopped doing because if something is outside the expectation and an error happens, the error should happen.
| await this.dataSource.query( | ||
| "DROP FUNCTION IF EXISTS sims.create_history_entry", | ||
| ); | ||
| await this.dataSource.query( |
There was a problem hiding this comment.
Minor, I do not recall if there was a reason not call all these DB commands in parallel.
It can be a quick improvement (outside PR scope).
| "DROP FUNCTION IF EXISTS sims.create_history_entry", | ||
| ); | ||
| await this.dataSource.query( | ||
| "DROP FUNCTION IF EXISTS sims.is_valid_system_lookup_key(TEXT,TEXT)", |
There was a problem hiding this comment.
Do we need the (TEXT,TEXT) at the end since line 13 does not have it?
There was a problem hiding this comment.
As discussed, the function with parameters requires it.
| }); | ||
| beforeEach(async () => { | ||
| // Clean up the system lookup configuration test entries before each test. | ||
| await db.systemLookupConfiguration.delete({ lookupKey: ILike("TEST_%") }); |
There was a problem hiding this comment.
Minor, the TEST_ can be a const.
| it("Should get the system lookup test entries for the category country when one or more test entries exist for the same category.", async () => { | ||
| // Arrange | ||
| // Create test system lookup entries for country. | ||
| const testCountryLookup1 = createFakeSystemLookupConfiguration( |
There was a problem hiding this comment.
Minor and not a blocker can be simplified as below.
const [testCountryLookup1, testCountryLookup2] = Array.from({
length: 2,
}).map((_, index) =>
createFakeSystemLookupConfiguration(
{
auditUser,
},
{
initialValues: {
lookupCategory: SystemLookupCategory.Country,
lookupKey: `TEST_CN${index}`,
lookupValue: `Test Country${index}`,
},
},
),
);
andrewsignori-aot
left a comment
There was a problem hiding this comment.
Amazing work with the system lookup, the check constraint, and the DB seeding adjustments. Only minor and non-blocker comments, hence approving.
| const testCountryLookup2 = createFakeSystemLookupConfiguration( | ||
| { | ||
| auditUser, | ||
| }, | ||
| { | ||
| initialValues: { | ||
| lookupCategory: SystemLookupCategory.Country, | ||
| lookupKey: "TEST_CN2", | ||
| lookupValue: "Test Country2", | ||
| }, | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Can we add a 3rd lookup category, anything other than a country (say Province) testing the part that it should not get returned.
There was a problem hiding this comment.
Adding 3rd lookup category was my first thought, but it requires updating the enum with 3rd category SystemLookupCategory.Some3rdCategory for the API to allow it. so i took this approach.
There was a problem hiding this comment.
It could have been tested with the existing Province category.
|

Institution profile updates - DB Migrations and Lookup data API
DB Migrations
Migration 1: DB migration to create the system-user if the system-user is not already present in DB.
Need for creating this migration: When insert scripts are executed as part of DB migrations, we require an audit-user as creator of inserted records and the audit-user can only be a system user in this case. But when these scripts execute on a clean DB, say E2E test database then there is no system-user available for the DB migrations because it is created only during nest application startup which happens after DB Migrations are completed. Hence we added a migration to create a system-user if the same does not already exist in the DB.
Migration 2: DB Migration to create the table
sims.system_lookup_configurationsto configure the lookup data under different lookup categories. This lookup service is a generic solution which is primarily created to act as a store/API to provide values to web clients that are required to load the components.Migration 3: DB Migration to create the STABLE function
sims.is_valid_system_lookup_keywhich can be used in a check constraint for columns in tables which is based on the lookup data key. For e.g. sims.institutions has the column country which has country code value from thesims.system_lookup_configurationsunder lookup categoryCountry.Migration 4: DB Migration to add new columns to
sims.institutionsand update one or more new columns based on the existing institution types.Rollback Evidence
System lookup Module and API
SystemLookupConfigurationControllerthat is accessible to all clients (except external) similar to dynamic form configuration controller.API E2E Tests
SystemLookupConfigurationController.