Skip to content

Commit

Permalink
Remove old donation and add new ones (#1674)
Browse files Browse the repository at this point in the history
  • Loading branch information
ae2079 authored Jul 10, 2024
1 parent 2666a56 commit 039617e
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm';

export class AddUseDonationBoxToDonation1719888339662
export class AddUseDonationBoxAndRelevantTxHashToDonation1720634068179
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
Expand Down Expand Up @@ -32,32 +32,6 @@ export class AddUseDonationBoxToDonation1719888339662
}),
);
}

const givethProjectId = 1;
const timeDiff = 60 * 1000; // 1 minute in milliseconds

await queryRunner.query(
`
WITH RelevantDonations AS (
SELECT d1.id AS donation1_id, d2.id AS donation2_id, d2."transactionId" AS relevant_tx_hash
FROM donation d1
JOIN donation d2 ON d1."userId" = d2."userId"
WHERE d1."projectId" = $1
AND d2."projectId" != $1
AND ABS(EXTRACT(EPOCH FROM (d1."createdAt" - d2."createdAt"))) <= $2
)
UPDATE donation
SET "useDonationBox" = true,
"relevantDonationTxHash" = CASE
WHEN donation."projectId" = $1 THEN RelevantDonations.relevant_tx_hash
ELSE NULL
END
FROM RelevantDonations
WHERE donation.id = RelevantDonations.donation1_id
OR donation.id = RelevantDonations.donation2_id;
`,
[givethProjectId, timeDiff],
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

interface DonationUpdate {
id: number;
useDonationBox: boolean;
relevantDonationTxHash: string | null;
}

export class FillUseDonationBoxAndRelevantTxHashInDonation1720634181001
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
const givethProjectId = 1;
const timeDiff = 60 * 1000; // 1 minute in milliseconds

// Load all donations into memory
const donations = await queryRunner.query(
`SELECT id, "userId", "projectId", "createdAt", "transactionId" FROM donation`,
);

// Calculate relevant donations
const updates: DonationUpdate[] = [];
const userDonations = donations.reduce(
(acc, donation) => {
const userId = donation.userId;
if (!acc[userId]) {
acc[userId] = [];
}
acc[userId].push(donation);
return acc;
},
{} as Record<number, any[]>,
);

for (const userId in userDonations) {
const userDonationList = userDonations[userId];
userDonationList.sort(
(a, b) =>
new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(),
);

for (let i = 0; i < userDonationList.length; i++) {
const donation = userDonationList[i];
if (donation.projectId === givethProjectId) {
let found = false;

// Check for donations after the current donation
for (let j = i + 1; j < userDonationList.length; j++) {
const nextDonation = userDonationList[j];
const timeDifference =
new Date(nextDonation.createdAt).getTime() -
new Date(donation.createdAt).getTime();
if (timeDifference <= timeDiff) {
if (nextDonation.projectId !== givethProjectId) {
updates.push({
id: donation.id,
useDonationBox: true,
relevantDonationTxHash: nextDonation.transactionId,
});
updates.push({
id: nextDonation.id,
useDonationBox: true,
relevantDonationTxHash: null,
});
found = true;
break;
}
} else {
break;
}
}

// Check for donations before the current donation if no relevant donation found
if (!found) {
for (let k = i - 1; k >= 0; k--) {
const prevDonation = userDonationList[k];
const timeDifference =
new Date(donation.createdAt).getTime() -
new Date(prevDonation.createdAt).getTime();
if (timeDifference <= timeDiff) {
if (prevDonation.projectId !== givethProjectId) {
updates.push({
id: donation.id,
useDonationBox: true,
relevantDonationTxHash: prevDonation.transactionId,
});
updates.push({
id: prevDonation.id,
useDonationBox: true,
relevantDonationTxHash: null,
});
break;
}
} else {
break;
}
}
}
}
}
}

// Perform batch update using a single query
const updateQuery = updates
.map(
update =>
`(${update.id}, ${update.useDonationBox}, ${
update.relevantDonationTxHash
? `'${update.relevantDonationTxHash}'`
: 'NULL'
})`,
)
.join(', ');

await queryRunner.query(
`
UPDATE donation AS d
SET "useDonationBox" = u."useDonationBox",
"relevantDonationTxHash" = u."relevantDonationTxHash"
FROM (VALUES ${updateQuery}) AS u(id, "useDonationBox", "relevantDonationTxHash")
WHERE d.id = u.id;
`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`
UPDATE donation
SET "useDonationBox" = false,
"relevantDonationTxHash" = NULL
WHERE "useDonationBox" = true;
`,
);
}
}

0 comments on commit 039617e

Please sign in to comment.