Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 23 additions & 0 deletions api/prisma/migrations/65_listing_cascade_unit_groups/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-- DropForeignKey
ALTER TABLE "unit_group" DROP CONSTRAINT "unit_group_listing_id_fkey";

-- DropForeignKey
ALTER TABLE "unit_group_ami_levels" DROP CONSTRAINT "unit_group_ami_levels_unit_group_id_fkey";

-- AlterTable
ALTER TABLE "application_snapshot" ALTER COLUMN "income_vouchers" DROP DEFAULT;

-- AlterTable
ALTER TABLE "applications" ALTER COLUMN "income_vouchers" DROP DEFAULT;

-- AlterTable
ALTER TABLE "user_notification_preferences" ALTER COLUMN "updated_at" DROP DEFAULT;

-- AlterTable
ALTER TABLE "user_notification_preferences_snapshot" ALTER COLUMN "updated_at" DROP DEFAULT;

-- AddForeignKey
ALTER TABLE "unit_group" ADD CONSTRAINT "unit_group_listing_id_fkey" FOREIGN KEY ("listing_id") REFERENCES "listings"("id") ON DELETE CASCADE ON UPDATE NO ACTION;

-- AddForeignKey
ALTER TABLE "unit_group_ami_levels" ADD CONSTRAINT "unit_group_ami_levels_unit_group_id_fkey" FOREIGN KEY ("unit_group_id") REFERENCES "unit_group"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
6 changes: 3 additions & 3 deletions api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ model AccessibilitySnapshot {
@@map("accessibility_snapshot")
}

// AcivityLog Section
// ActivityLog Section
model ActivityLog {
id String @id() @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6)
Expand Down Expand Up @@ -1793,7 +1793,7 @@ model UnitGroup {
totalAvailable Int? @map("total_available")
totalCount Int? @map("total_count")

listings Listings? @relation(fields: [listingId], references: [id], onDelete: NoAction, onUpdate: NoAction)
listings Listings? @relation(fields: [listingId], references: [id], onDelete: Cascade, onUpdate: NoAction)
unitGroupAmiLevels UnitGroupAmiLevels[]
unitTypes UnitTypes[]

Expand Down Expand Up @@ -1846,7 +1846,7 @@ model UnitGroupAmiLevels {
percentageOfIncomeValue Decimal? @map("percentage_of_income_value") @db.Decimal
unitGroupId String? @map("unit_group_id") @db.Uuid

unitGroup UnitGroup? @relation(fields: [unitGroupId], references: [id], onDelete: NoAction, onUpdate: NoAction)
unitGroup UnitGroup? @relation(fields: [unitGroupId], references: [id], onDelete: Cascade, onUpdate: NoAction)
amiChart AmiChart? @relation(fields: [amiChartId], references: [id], onDelete: NoAction, onUpdate: NoAction)

@@map("unit_group_ami_levels")
Expand Down
28 changes: 25 additions & 3 deletions api/src/services/external-listing.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,28 @@ export class ExternalListingService {
throw new HttpException('Target jurisdiction not found', 500);
}

let listingIdsToDelete = [];
const buildingAddressIdsToDelete = [];
const listingIdsToDelete = [];

// query for existing external listings within the system
const currentExternalListings = await this.prisma.listings.findMany({
select: { id: true, contentUpdatedAt: true, externalListingId: true },
select: {
id: true,
buildingAddressId: true,
contentUpdatedAt: true,
externalListingId: true,
},
where: {
externalJurisdictionId: externalJurisdiction.id,
jurisdictionId: jurisdictionId,
},
});

if (listings.length === 0) {
listingIdsToDelete = currentExternalListings.map((listing) => listing.id);
currentExternalListings.forEach((listing) => {
buildingAddressIdsToDelete.push(listing.buildingAddressId);
listingIdsToDelete.push(listing.id);
});
} else {
// query and compare reserved community types
const internalReservedCommunityTypes =
Expand Down Expand Up @@ -183,6 +192,10 @@ export class ExternalListingService {
await this.prisma.listings.delete({
where: { id: existingListing.id },
});
await this.prisma.address.delete({
where: { id: existingListing.buildingAddressId },
});

// recreate with updated data
this.createExternalListing(
combinedRCTs,
Expand All @@ -198,6 +211,7 @@ export class ExternalListingService {
}
} else {
// add to list for deletion
buildingAddressIdsToDelete.push(existingListing.buildingAddressId);
listingIdsToDelete.push(existingListing.id);
}
}
Expand Down Expand Up @@ -232,6 +246,14 @@ export class ExternalListingService {
},
},
});

await this.prisma.address.deleteMany({
where: {
id: {
in: buildingAddressIdsToDelete,
},
},
});
}

return {
Expand Down
4 changes: 4 additions & 0 deletions api/test/integration/application.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,7 @@ describe('Application Controller Tests', () => {
data: {
listings: { connect: { id: listing2.id } },
confirmationCode: randomUUID(),
incomeVouchers: [],
preferences: [],
submissionType: ApplicationSubmissionTypeEnum.electronical,
status: ApplicationStatusEnum.submitted,
Expand All @@ -808,6 +809,7 @@ describe('Application Controller Tests', () => {
data: {
listings: { connect: { id: listing2.id } },
confirmationCode: randomUUID(),
incomeVouchers: [],
preferences: [],
submissionType: ApplicationSubmissionTypeEnum.electronical,
status: ApplicationStatusEnum.submitted,
Expand Down Expand Up @@ -1215,6 +1217,7 @@ describe('Application Controller Tests', () => {
data: {
listings: { connect: { id: listing2.id } },
confirmationCode: randomUUID(),
incomeVouchers: [],
preferences: [],
submissionType: ApplicationSubmissionTypeEnum.electronical,
status: ApplicationStatusEnum.submitted,
Expand All @@ -1226,6 +1229,7 @@ describe('Application Controller Tests', () => {
data: {
listings: { connect: { id: listing2.id } },
confirmationCode: randomUUID(),
incomeVouchers: [],
preferences: [],
submissionType: ApplicationSubmissionTypeEnum.electronical,
status: ApplicationStatusEnum.submitted,
Expand Down
5 changes: 5 additions & 0 deletions api/test/integration/lottery.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@ describe('Lottery Controller Tests', () => {
lotteryStatus: LotteryStatusEnum.releasedToPartners,
applications: [
{
incomeVouchers: [],
preferences: [],
status: ApplicationStatusEnum.submitted,
confirmationCode: 'ABCD1234',
Expand All @@ -1160,6 +1161,7 @@ describe('Lottery Controller Tests', () => {
},
},
{
incomeVouchers: [],
preferences: [],
status: ApplicationStatusEnum.submitted,
confirmationCode: 'EFGH5678',
Expand All @@ -1175,6 +1177,7 @@ describe('Lottery Controller Tests', () => {
},
},
{
incomeVouchers: [],
preferences: [],
status: ApplicationStatusEnum.submitted,
confirmationCode: 'IJKL9012',
Expand All @@ -1190,6 +1193,7 @@ describe('Lottery Controller Tests', () => {
},
},
{
incomeVouchers: [],
preferences: [],
status: ApplicationStatusEnum.submitted,
confirmationCode: 'ABC678',
Expand All @@ -1205,6 +1209,7 @@ describe('Lottery Controller Tests', () => {
},
},
{
incomeVouchers: [],
preferences: [],
status: ApplicationStatusEnum.submitted,
confirmationCode: 'MNOP3456',
Expand Down
36 changes: 26 additions & 10 deletions api/test/unit/services/external-listing.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('Testing external listing service', () => {
let httpService: HttpService;
let prisma: PrismaService;
let service: ExternalListingService;
const externalURL = 'example.com';
const externalURL = 'https://www.example.com';

beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
Expand Down Expand Up @@ -153,7 +153,7 @@ describe('Testing external listing service', () => {

await expect(
service.ingest({
externalURL: 'example.com',
externalURL: externalURL,
jurisdictionId: randomUUID(),
targetName: 'mismatch',
}),
Expand Down Expand Up @@ -187,7 +187,7 @@ describe('Testing external listing service', () => {

await expect(
service.ingest({
externalURL: 'example.com',
externalURL: externalURL,
jurisdictionId: randomUUID(),
targetName: 'mismatch',
}),
Expand All @@ -199,7 +199,6 @@ describe('Testing external listing service', () => {
const externalListingDate = new Date();
const externalListingId = randomUUID();
const externalRCTId = randomUUID();
const externalURL = 'example.com';
const externalURTId = randomUUID();
const externalUTId = randomUUID();

Expand All @@ -217,7 +216,7 @@ describe('Testing external listing service', () => {
listings: [
{
id: externalListingId,
contentUpdateAt: externalListingDate,
contentUpdatedAt: externalListingDate,
jurisdictionId: externalJurisdictionId,
},
],
Expand Down Expand Up @@ -309,7 +308,7 @@ describe('Testing external listing service', () => {
listings: [
{
id: externalListingId,
contentUpdateAt: externalListingDate,
contentUpdatedAt: externalListingDate,
jurisdictionId: externalJurisdictionId,
},
],
Expand Down Expand Up @@ -349,6 +348,7 @@ describe('Testing external listing service', () => {
.mockImplementationOnce(() => of(mockExternalDetailsResponse))
.mockImplementationOnce(() => of(mockExternalListingResponse));

const internalBuildingAddressId = randomUUID();
const internalJurisdictionId = randomUUID();
const internalListingDate = dayjs(new Date())
.subtract(1, 'days')
Expand All @@ -358,11 +358,13 @@ describe('Testing external listing service', () => {
const internalURTId = randomUUID();
const internalUTId = randomUUID();

prisma.address.delete = jest.fn().mockResolvedValue(undefined);
prisma.listings.create = jest.fn().mockResolvedValue({});
prisma.listings.delete = jest.fn().mockResolvedValue(undefined);
prisma.listings.findMany = jest.fn().mockResolvedValue([
{
id: internalListingId,
buildingAddressId: internalBuildingAddressId,
contentUpdatedAt: internalListingDate,
externalListingId,
},
Expand All @@ -387,6 +389,9 @@ describe('Testing external listing service', () => {

expect(response.success).toEqual(true);

expect(prisma.address.delete).toHaveBeenCalledWith({
where: { id: internalBuildingAddressId },
});
expect(prisma.listings.delete).toHaveBeenCalledWith({
where: { id: internalListingId },
});
Expand All @@ -398,7 +403,6 @@ describe('Testing external listing service', () => {
const externalListingDate = new Date();
const externalListingId = randomUUID();
const externalRCTId = randomUUID();
const externalURL = 'example.com';
const externalURTId = randomUUID();
const externalUTId = randomUUID();

Expand All @@ -416,7 +420,7 @@ describe('Testing external listing service', () => {
listings: [
{
id: externalListingId,
contentUpdateAt: externalListingDate,
contentUpdatedAt: externalListingDate,
jurisdictionId: externalJurisdictionId,
},
],
Expand All @@ -432,6 +436,7 @@ describe('Testing external listing service', () => {
.spyOn(httpService, 'get')
.mockImplementationOnce(() => of(mockExternalDetailsResponse));

const internalBuildingAddressId = randomUUID();
const internalJurisdictionId = randomUUID();
const internalListingId = randomUUID();
const internalRCTId = randomUUID();
Expand All @@ -442,6 +447,7 @@ describe('Testing external listing service', () => {
prisma.listings.findMany = jest.fn().mockResolvedValue([
{
id: internalListingId,
buildingAddressId: internalBuildingAddressId,
contentUpdatedAt: externalListingDate,
externalListingId,
},
Expand All @@ -467,7 +473,12 @@ describe('Testing external listing service', () => {
expect(response.success).toEqual(true);

expect(prisma.listings.findMany).toHaveBeenCalledExactlyOnceWith({
select: { id: true, contentUpdatedAt: true, externalListingId: true },
select: {
id: true,
buildingAddressId: true,
contentUpdatedAt: true,
externalListingId: true,
},
where: {
externalJurisdictionId: externalJurisdictionId,
jurisdictionId: internalJurisdictionId,
Expand All @@ -490,7 +501,6 @@ describe('Testing external listing service', () => {
it('should delete a listing if no longer returned from external system', async () => {
const externalJurisdictionId = randomUUID();
const externalRCTId = randomUUID();
const externalURL = 'example.com';
const externalURTId = randomUUID();
const externalUTId = randomUUID();

Expand Down Expand Up @@ -518,13 +528,16 @@ describe('Testing external listing service', () => {
.spyOn(httpService, 'get')
.mockImplementationOnce(() => of(mockExternalDetailsResponse));

const internalBuildingAddressId = randomUUID();
const internalJurisdictionId = randomUUID();
const internalListingId = randomUUID();

prisma.address.deleteMany = jest.fn().mockResolvedValue(undefined);
prisma.listings.deleteMany = jest.fn().mockResolvedValue(undefined);
prisma.listings.findMany = jest.fn().mockResolvedValue([
{
id: internalListingId,
buildingAddressId: internalBuildingAddressId,
contentUpdatedAt: new Date(),
externalListingId: randomUUID(),
},
Expand All @@ -545,6 +558,9 @@ describe('Testing external listing service', () => {
expect(prisma.unitRentTypes.findMany).not.toHaveBeenCalled();
expect(prisma.unitTypes.findMany).not.toHaveBeenCalled();

expect(prisma.address.deleteMany).toHaveBeenCalledWith({
where: { id: { in: [internalBuildingAddressId] } },
});
expect(prisma.listings.deleteMany).toHaveBeenCalledWith({
where: { id: { in: [internalListingId] } },
});
Expand Down
Loading