Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a473b7e
feat: application create and read refactor
mcgarrye Dec 16, 2025
33ca73e
Merge branch 'main' into 5147/msq-refactor-application-service
mcgarrye Dec 17, 2025
2597cb5
Merge branch 'main' into 5147/msq-refactor-application-service
mcgarrye Dec 17, 2025
54eb283
feat: update tests with new fields
mcgarrye Dec 17, 2025
e69531b
feat: fix typing error
mcgarrye Dec 17, 2025
3e6c7da
Merge branch 'main' into 5147/msq-refactor-application-service
mcgarrye Dec 22, 2025
b4c0f71
Merge branch 'main' into 5147/msq-refactor-application-service
mcgarrye Dec 23, 2025
1837c52
fix: flakey test
mcgarrye Dec 23, 2025
cdae353
fix: adjust flaky test
mcgarrye Dec 23, 2025
a12e534
fix: toContainEqual
mcgarrye Dec 23, 2025
cffa9bc
feat: geocoding refactor
mcgarrye Dec 23, 2025
42fbfbf
Merge branch 'main' into 5147/msq-refactor-application-service
mcgarrye Jan 2, 2026
52abbeb
feat: follow export standards
mcgarrye Jan 2, 2026
8bdb897
Merge branch 'main' into 5147/msq-refactor-application-service
mcgarrye Jan 6, 2026
8a3996b
Merge branch '5147/msq-refactor-application-service' into 5705/msq-re…
mcgarrye Jan 6, 2026
2d881d7
feat: false flow testing
mcgarrye Jan 6, 2026
2797d4f
Merge branch 'main' into 5705/msq-refactor-geocoding-service
mcgarrye Jan 6, 2026
abaeb97
feat: adjust imports
mcgarrye Jan 6, 2026
1dfccbb
Merge branch 'main' into 5705/msq-refactor-geocoding-service
mcgarrye Jan 6, 2026
174cc07
Merge branch 'main' into 5705/msq-refactor-geocoding-service
mcgarrye Jan 6, 2026
d2138a6
Merge branch 'main' into 5705/msq-refactor-geocoding-service
mcgarrye Jan 7, 2026
4b338df
Merge branch 'main' into 5705/msq-refactor-geocoding-service
mcgarrye Jan 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- DropForeignKey
ALTER TABLE "application_selection_options" DROP CONSTRAINT "application_selection_options_application_selection_id_fkey";

-- DropForeignKey
ALTER TABLE "application_selections" DROP CONSTRAINT "application_selections_application_id_fkey";

-- AddForeignKey
ALTER TABLE "application_selection_options" ADD CONSTRAINT "application_selection_options_application_selection_id_fkey" FOREIGN KEY ("application_selection_id") REFERENCES "application_selections"("id") ON DELETE CASCADE ON UPDATE NO ACTION;

-- AddForeignKey
ALTER TABLE "application_selections" ADD CONSTRAINT "application_selections_application_id_fkey" FOREIGN KEY ("application_id") REFERENCES "applications"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
4 changes: 2 additions & 2 deletions api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ model ApplicationSelectionOptions {
isGeocodingVerified Boolean? @map("is_geocoding_verified")
multiselectOptionId String @map("multiselect_option_id") @db.Uuid
addressHolderAddress Address? @relation("application_selection_address", fields: [addressHolderAddressId], references: [id], onDelete: NoAction, onUpdate: NoAction)
applicationSelections ApplicationSelections @relation(fields: [applicationSelectionId], references: [id], onDelete: NoAction, onUpdate: NoAction)
applicationSelection ApplicationSelections @relation(fields: [applicationSelectionId], references: [id], onDelete: Cascade, onUpdate: NoAction)
multiselectOption MultiselectOptions @relation(fields: [multiselectOptionId], references: [id], onDelete: NoAction, onUpdate: NoAction)

@@map("application_selection_options")
Expand All @@ -195,7 +195,7 @@ model ApplicationSelections {
applicationId String @map("application_id") @db.Uuid
hasOptedOut Boolean? @map("has_opted_out")
multiselectQuestionId String @map("multiselect_question_id") @db.Uuid
application Applications @relation(fields: [applicationId], references: [id], onDelete: NoAction, onUpdate: NoAction)
application Applications @relation(fields: [applicationId], references: [id], onDelete: Cascade, onUpdate: NoAction)
multiselectQuestion MultiselectQuestions @relation(fields: [multiselectQuestionId], references: [id], onDelete: NoAction, onUpdate: NoAction)
selections ApplicationSelectionOptions[]

Expand Down
1 change: 1 addition & 0 deletions api/prisma/seed-helpers/multiselect-question-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,6 @@ const multiselectOptionFactoryV2 = (numberToMake: number) => {
return [...new Array(numberToMake)].map((_, index) => ({
name: randomNoun(),
ordinal: index,
shouldCollectAddress: index % 2 === 0,
}));
};
17 changes: 17 additions & 0 deletions api/src/dtos/addresses/address-update.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Expose } from 'class-transformer';
import { IsString, IsUUID } from 'class-validator';
import { ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { Address } from './address.dto';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';

export class AddressUpdate extends OmitType(Address, [
'id',
'createdAt',
'updatedAt',
]) {
@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@IsUUID(4, { groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional()
id?: string;
}
23 changes: 21 additions & 2 deletions api/src/dtos/applications/application-create.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
import { OmitType } from '@nestjs/swagger';
import { Expose, Type } from 'class-transformer';
import { ArrayMaxSize, ValidateNested } from 'class-validator';
import { ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { ApplicationUpdate } from './application-update.dto';
import ApplicationSelectionCreate from './application-selection-create.dto';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';

export class ApplicationCreate extends OmitType(ApplicationUpdate, ['id']) {}
export class ApplicationCreate extends OmitType(ApplicationUpdate, [
'id',
'applicationSelections',
]) {
// TODO: Temporarily optional until after MSQ refactor
@Expose()
// @IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ArrayMaxSize(64, { groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true })
@Type(() => ApplicationSelectionCreate)
@ApiPropertyOptional({
type: ApplicationSelectionCreate,
isArray: true,
})
applicationSelections?: ApplicationSelectionCreate[];
}
24 changes: 24 additions & 0 deletions api/src/dtos/applications/application-selection-create.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ApiProperty, OmitType } from '@nestjs/swagger';
import { Expose, Type } from 'class-transformer';
import { IsDefined, ValidateNested } from 'class-validator';
import ApplicationSelectionUpdate from './application-selection-update.dto';
import ApplicationSelectionOptionCreate from './application-selection-option-create.dto';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';

class ApplicationSelectionCreate extends OmitType(ApplicationSelectionUpdate, [
'id',
'application',
'selections',
]) {
@Expose()
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true })
@Type(() => ApplicationSelectionOptionCreate)
@ApiProperty({
type: ApplicationSelectionOptionCreate,
isArray: true,
})
selections: ApplicationSelectionOptionCreate[];
}

export { ApplicationSelectionCreate as default, ApplicationSelectionCreate };
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { OmitType } from '@nestjs/swagger';
import ApplicationSelectionOptionUpdate from './application-selection-option-update.dto';

class ApplicationSelectionOptionCreate extends OmitType(
ApplicationSelectionOptionUpdate,
['id'],
) {}

export {
ApplicationSelectionOptionCreate as default,
ApplicationSelectionOptionCreate,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { Expose, Type } from 'class-transformer';
import { IsString, IsUUID, ValidateNested } from 'class-validator';
import ApplicationSelectionOption from './application-selection-option.dto';
import { AddressUpdate } from '../addresses/address-update.dto';
import { IdDTO } from '../shared/id.dto';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';

class ApplicationSelectionOptionUpdate extends OmitType(
ApplicationSelectionOption,
[
'id',
'createdAt',
'updatedAt',
'addressHolderAddress',
'applicationSelection',
],
) {
@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@IsUUID(4, { groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional()
id?: string;

@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => AddressUpdate)
@ApiPropertyOptional({ type: AddressUpdate })
addressHolderAddress?: AddressUpdate;

@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => IdDTO)
@ApiPropertyOptional({ type: IdDTO })
applicationSelection?: IdDTO;
}

export {
ApplicationSelectionOptionUpdate as default,
ApplicationSelectionOptionUpdate,
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import {
import { AbstractDTO } from '../shared/abstract.dto';
import { IdDTO } from '../shared/id.dto';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';
import { Address } from '../addresses/address.dto';

class ApplicationSelectionOptions extends AbstractDTO {
class ApplicationSelectionOption extends AbstractDTO {
@Expose()
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => IdDTO)
@ApiProperty({ type: IdDTO })
addressHolderAddress?: IdDTO;
@Type(() => Address)
@ApiProperty({ type: Address })
addressHolderAddress?: Address;

@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
Expand All @@ -42,10 +43,9 @@ class ApplicationSelectionOptions extends AbstractDTO {

@Expose()
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => IdDTO)
@ApiProperty({ type: IdDTO })
multiselectOption: IdDTO;
}

export { ApplicationSelectionOptions as default, ApplicationSelectionOptions };
export { ApplicationSelectionOption as default, ApplicationSelectionOption };
31 changes: 31 additions & 0 deletions api/src/dtos/applications/application-selection-update.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ApiProperty, ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { Expose, Type } from 'class-transformer';
import { IsDefined, IsString, IsUUID, ValidateNested } from 'class-validator';
import ApplicationSelection from './application-selection.dto';
import ApplicationSelectionOptionUpdate from './application-selection-option-update.dto';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';

class ApplicationSelectionUpdate extends OmitType(ApplicationSelection, [
'id',
'createdAt',
'updatedAt',
'selections',
]) {
@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@IsUUID(4, { groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional()
id?: string;

@Expose()
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true })
@Type(() => ApplicationSelectionOptionUpdate)
@ApiProperty({
type: ApplicationSelectionOptionUpdate,
isArray: true,
})
selections: ApplicationSelectionOptionUpdate[];
}

export { ApplicationSelectionUpdate as default, ApplicationSelectionUpdate };
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Expose, Type } from 'class-transformer';
import { ValidateNested, IsBoolean, IsDefined } from 'class-validator';
import ApplicationSelectionOptions from './application-selection-options.dto';
import {
ValidateNested,
IsBoolean,
IsDefined,
IsString,
} from 'class-validator';
import ApplicationSelectionOption from './application-selection-option.dto';
import { AbstractDTO } from '../shared/abstract.dto';
import { IdDTO } from '../shared/id.dto';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';

class ApplicationSelections extends AbstractDTO {
class ApplicationSelection extends AbstractDTO {
@Expose()
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
Expand All @@ -21,17 +26,16 @@ class ApplicationSelections extends AbstractDTO {

@Expose()
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => IdDTO)
@ApiProperty({ type: IdDTO })
multiselectQuestion: IdDTO;

@Expose()
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => ApplicationSelectionOptions)
@ApiProperty({ type: ApplicationSelectionOptions })
selections: ApplicationSelectionOptions[];
@Type(() => ApplicationSelectionOption)
@ApiProperty({ type: ApplicationSelectionOption })
selections: ApplicationSelectionOption[];
}

export { ApplicationSelections as default, ApplicationSelections };
export { ApplicationSelection as default, ApplicationSelection };
56 changes: 35 additions & 21 deletions api/src/dtos/applications/application-update.dto.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,65 @@
import { ApiProperty, OmitType } from '@nestjs/swagger';
import { Expose, Type } from 'class-transformer';
import { ArrayMaxSize, ValidateNested } from 'class-validator';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';
import { AddressCreate } from '../addresses/address-create.dto';
import { ApiProperty, ApiPropertyOptional, OmitType } from '@nestjs/swagger';
import { AccessibilityUpdate } from './accessibility-update.dto';
import { AlternateContactUpdate } from './alternate-contact-update.dto';
import { ApplicantUpdate } from './applicant-update.dto';
import { Application } from './application.dto';
import ApplicationSelectionUpdate from './application-selection-update.dto';
import { DemographicUpdate } from './demographic-update.dto';
import { HouseholdMemberUpdate } from './household-member-update.dto';
import { AddressCreate } from '../addresses/address-create.dto';
import { IdDTO } from '../shared/id.dto';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';

export class ApplicationUpdate extends OmitType(Application, [
'createdAt',
'updatedAt',
'deletedAt',
'accessibility',
'alternateContact',
'applicant',
'applicationsMailingAddress',
'applicationLotteryPositions',
'applicationSelections',
'applicationsAlternateAddress',
'alternateContact',
'accessibility',
'applicationsMailingAddress',
'confirmationCode',
'demographics',
'flagged',
'householdMember',
'markedAsDuplicate',
'flagged',
'confirmationCode',
'preferredUnitTypes',
'applicationLotteryPositions',
]) {
@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => AccessibilityUpdate)
@ApiProperty({ type: AccessibilityUpdate })
accessibility: AccessibilityUpdate;

@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => AlternateContactUpdate)
@ApiProperty({ type: AlternateContactUpdate })
alternateContact: AlternateContactUpdate;

@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => ApplicantUpdate)
@ApiProperty({ type: ApplicantUpdate })
applicant: ApplicantUpdate;

// TODO: Temporarily optional until after MSQ refactor
@Expose()
// @IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ArrayMaxSize(64, { groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true })
@Type(() => ApplicationSelectionUpdate)
@ApiPropertyOptional({
type: ApplicationSelectionUpdate,
isArray: true,
})
applicationSelections?: ApplicationSelectionUpdate[];

@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => AddressCreate)
Expand All @@ -46,18 +72,6 @@ export class ApplicationUpdate extends OmitType(Application, [
@ApiProperty({ type: AddressCreate })
applicationsAlternateAddress: AddressCreate;

@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => AlternateContactUpdate)
@ApiProperty({ type: AlternateContactUpdate })
alternateContact: AlternateContactUpdate;

@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => AccessibilityUpdate)
@ApiProperty({ type: AccessibilityUpdate })
accessibility: AccessibilityUpdate;

@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default] })
@Type(() => DemographicUpdate)
Expand Down
10 changes: 5 additions & 5 deletions api/src/dtos/applications/application.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { Demographic } from './demographic.dto';
import { HouseholdMember } from './household-member.dto';
import { UnitType } from '../unit-types/unit-type.dto';
import { ApplicationLotteryPosition } from './application-lottery-position.dto';
import ApplicationSelections from './application-selections.dto';
import ApplicationSelection from './application-selection.dto';

export class Application extends AbstractDTO {
@Expose()
Expand Down Expand Up @@ -262,16 +262,16 @@ export class Application extends AbstractDTO {
householdMember: HouseholdMember[];

// TODO: Temporarily optional until after MSQ refactor
// @Expose()
@Expose()
// @IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ArrayMaxSize(64, { groups: [ValidationsGroupsEnum.default] })
@ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true })
@Type(() => ApplicationSelections)
@Type(() => ApplicationSelection)
@ApiPropertyOptional({
type: ApplicationSelections,
type: ApplicationSelection,
isArray: true,
})
applicationSelections?: ApplicationSelections[];
applicationSelections?: ApplicationSelection[];

@Expose()
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
Expand Down
Loading