Skip to content

Commit

Permalink
add migration and columns for totals in project entity (#1571)
Browse files Browse the repository at this point in the history
* add migration and columns for totals in project entity

* add service to update project totals

* add filling the value for new fields
  • Loading branch information
CarlosQ96 committed May 23, 2024
1 parent ef4742c commit dac109b
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 37 deletions.
52 changes: 52 additions & 0 deletions migration/1715728347907-AddCalculatedFieldAsColumnsForProject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddCalculatedFieldAsColumnsForProject1715728347907
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE "project"
ADD COLUMN IF NOT EXISTS "sumDonationValueUsdForActiveQfRound" DOUBLE PRECISION DEFAULT 0;
`);

await queryRunner.query(`
ALTER TABLE "project"
ADD COLUMN IF NOT EXISTS "sumDonationValueUsd" DOUBLE PRECISION DEFAULT 0;
`);

// Add new integer columns for counting unique donors with 'IF NOT EXISTS'
await queryRunner.query(`
ALTER TABLE "project"
ADD COLUMN IF NOT EXISTS "countUniqueDonorsForActiveQfRound" INTEGER DEFAULT 0;
`);

await queryRunner.query(`
ALTER TABLE "project"
ADD COLUMN IF NOT EXISTS "countUniqueDonors" INTEGER DEFAULT 0;
`);

await queryRunner.query(`
UPDATE "project"
SET "countUniqueDonors" = pds."uniqueDonorsCount",
"sumDonationValueUsd" = pds."sumVerifiedDonations"
FROM "project_donation_summary_view" AS pds
WHERE "project"."id" = pds."projectId";
`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
// Use 'IF EXISTS' in the DROP statement to avoid errors in case the column does not exist
await queryRunner.query(
`ALTER TABLE "project" DROP COLUMN IF EXISTS "sumDonationValueUsdForActiveQfRound"`,
);
await queryRunner.query(
`ALTER TABLE "project" DROP COLUMN IF EXISTS "sumDonationValueUsd"`,
);
await queryRunner.query(
`ALTER TABLE "project" DROP COLUMN IF EXISTS "countUniqueDonorsForActiveQfRound"`,
);
await queryRunner.query(
`ALTER TABLE "project" DROP COLUMN IF EXISTS "countUniqueDonors"`,
);
}
}
41 changes: 8 additions & 33 deletions src/entities/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ import { Category } from './category';
import { FeaturedUpdate } from './featuredUpdate';
import { getHtmlTextSummary } from '../utils/utils';
import { QfRound } from './qfRound';
import {
countUniqueDonors,
countUniqueDonorsForRound,
sumDonationValueUsd,
sumDonationValueUsdForQfRound,
} from '../repositories/donationRepository';
import {
getProjectDonationsSqrtRootSum,
getQfRoundTotalProjectsDonationsSum,
Expand Down Expand Up @@ -474,41 +468,22 @@ export class Project extends BaseEntity {
createdAt: new Date(),
}).save();
}
/**
* Custom Query Builders to chain together
*/

@Field(_type => Float, { nullable: true })
async sumDonationValueUsdForActiveQfRound() {
const activeQfRound = this.getActiveQfRound();
return activeQfRound
? await sumDonationValueUsdForQfRound({
projectId: this.id,
qfRoundId: activeQfRound.id,
})
: 0;
}
@Column({ type: 'float', nullable: true })
sumDonationValueUsdForActiveQfRound: number;

@Field(_type => Float, { nullable: true })
async sumDonationValueUsd() {
return await sumDonationValueUsd(this.id);
}
@Column({ type: 'float', nullable: true })
sumDonationValueUsd: number;

@Field(_type => Int, { nullable: true })
async countUniqueDonorsForActiveQfRound() {
const activeQfRound = this.getActiveQfRound();
return activeQfRound
? await countUniqueDonorsForRound({
projectId: this.id,
qfRoundId: activeQfRound.id,
})
: 0;
}
@Column({ type: 'int', nullable: true })
countUniqueDonorsForActiveQfRound: number;

@Field(_type => Int, { nullable: true })
async countUniqueDonors() {
return await countUniqueDonors(this.id);
}
@Column({ type: 'int', nullable: true })
countUniqueDonors: number;

// In your main class
@Field(_type => EstimatedMatching, { nullable: true })
Expand Down
8 changes: 4 additions & 4 deletions src/resolvers/projectResolver.allProject.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ function allProjectsTestCases() {
getHtmlTextSummary(project.description),
);
assert.isNull(project.estimatedMatching);
assert.exists(project.sumDonationValueUsd);
assert.exists(project.sumDonationValueUsdForActiveQfRound);
assert.exists(project.countUniqueDonorsForActiveQfRound);
assert.exists(project.countUniqueDonors);
assert.isNull(project.sumDonationValueUsd);
assert.isNull(project.sumDonationValueUsdForActiveQfRound);
assert.isNull(project.countUniqueDonorsForActiveQfRound);
assert.isNull(project.countUniqueDonors);
});
});

Expand Down
3 changes: 3 additions & 0 deletions src/services/donationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { getTransactionInfoFromNetwork } from './chains';
import { getEvmTransactionTimestamp } from './chains/evm/transactionService';
import { getOrttoPersonAttributes } from '../adapters/notifications/NotificationCenterAdapter';
import { CustomToken, getTokenPrice } from './priceService';
import { updateProjectStatistics } from './projectService';

export const TRANSAK_COMPLETED_STATUS = 'COMPLETED';

Expand Down Expand Up @@ -369,6 +370,8 @@ export const syncDonationStatusWithBlockchainNetwork = async (params: {
await refreshProjectEstimatedMatchingView();
await refreshProjectDonationSummaryView();

await updateProjectStatistics(donation.projectId);

const donationStats = await getUserDonationStats(donation.userId);
const donor = await findUserById(donation.userId);

Expand Down
36 changes: 36 additions & 0 deletions src/services/projectService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Project } from '../entities/project';
import {
countUniqueDonors,
countUniqueDonorsForRound,
sumDonationValueUsd,
sumDonationValueUsdForQfRound,
} from '../repositories/donationRepository';
import { findProjectById } from '../repositories/projectRepository';

export const getAppropriateSlug = async (
slugBase: string,
Expand All @@ -22,6 +29,35 @@ export const getAppropriateSlug = async (
return slug;
};

export const updateProjectStatistics = async (projectId: number) => {
const project = await findProjectById(projectId);
if (!project) return;

const activeQfRound = project.getActiveQfRound();
if (activeQfRound) {
project.sumDonationValueUsdForActiveQfRound =
await sumDonationValueUsdForQfRound({
projectId: project.id,
qfRoundId: activeQfRound.id,
});
project.countUniqueDonorsForActiveQfRound = await countUniqueDonorsForRound(
{
projectId: project.id,
qfRoundId: activeQfRound.id,
},
);
}

if (!activeQfRound) {
project.sumDonationValueUsdForActiveQfRound = 0;
project.countUniqueDonorsForActiveQfRound = 0;
}

project.sumDonationValueUsd = await sumDonationValueUsd(project.id);
project.countUniqueDonors = await countUniqueDonors(project.id);
await project.save();
};

// Current Formula: will be changed possibly in the future
export const getQualityScore = (description, hasImageUpload, heartCount?) => {
const heartScore = 10;
Expand Down

0 comments on commit dac109b

Please sign in to comment.