Skip to content
Open
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
7 changes: 3 additions & 4 deletions src/entities/projectQfRound.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Field, ID, ObjectType, Float, Int } from 'type-graphql';
import {
PrimaryColumn,
PrimaryGeneratedColumn,
Column,
Entity,
ManyToOne,
BaseEntity,
CreateDateColumn,
UpdateDateColumn,
Index,
PrimaryColumn,
} from 'typeorm';
import { Project } from './project';
import { QfRound } from './qfRound';
Expand All @@ -16,8 +16,7 @@ import { QfRound } from './qfRound';
@ObjectType()
export class ProjectQfRound extends BaseEntity {
@Field(_type => ID)
@Column({ generated: 'increment' })
@Index()
@PrimaryGeneratedColumn()
id: number;

@Field(_type => ID)
Expand Down
32 changes: 18 additions & 14 deletions src/repositories/projectRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1169,21 +1169,25 @@ function findQfRoundProjectsTestCases() {
await project2.save();

// Create ProjectQfRound entries with different donation amounts
const projectQfRound1 = ProjectQfRound.create({
projectId: project1.id,
qfRoundId: qfRound.id,
sumDonationValueUsd: 100,
countUniqueDonors: 5,
});
await projectQfRound1.save();
await ProjectQfRound.upsert(
{
projectId: project1.id,
qfRoundId: qfRound.id,
sumDonationValueUsd: 100,
countUniqueDonors: 5,
},
['projectId', 'qfRoundId'],
);

const projectQfRound2 = ProjectQfRound.create({
projectId: project2.id,
qfRoundId: qfRound.id,
sumDonationValueUsd: 500,
countUniqueDonors: 10,
});
await projectQfRound2.save();
await ProjectQfRound.upsert(
{
projectId: project2.id,
qfRoundId: qfRound.id,
sumDonationValueUsd: 500,
countUniqueDonors: 10,
},
['projectId', 'qfRoundId'],
);
Comment on lines +1172 to +1190
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the entity schema supports upsert on composite key.

The upsert operations specify ['projectId', 'qfRoundId'] as the conflict target, which requires either:

  1. A composite primary key on (projectId, qfRoundId), OR
  2. A unique constraint on (projectId, qfRoundId)

According to the AI summary, ProjectQfRound.id was changed to PrimaryGeneratedColumn while projectId and qfRoundId "remain declared with PrimaryColumn," and "no new unique constraint added." This is problematic because:

  • TypeORM doesn't allow multiple separate primary keys (id as PrimaryGeneratedColumn + projectId/qfRoundId as PrimaryColumn would conflict)
  • If only id is the primary key and no unique constraint exists on (projectId, qfRoundId), upsert will fail to detect conflicts and may create duplicate rows

Run the following script to verify the entity structure:


🏁 Script executed:

#!/bin/bash
# Description: Check ProjectQfRound entity definition for primary key and unique constraints

# Search for the entity definition
ast-grep --pattern $'@Entity()
export class ProjectQfRound {
  $$$
}'

# Look for primary key decorators
rg -nP --type=ts -A2 '@(PrimaryColumn|PrimaryGeneratedColumn)' src/entities/projectQfRound.ts

# Check for unique constraints
rg -nP --type=ts -C3 '@(Unique|Index.*unique)' src/entities/projectQfRound.ts

Length of output: 157


Ensure upsert conflict columns have a matching unique constraint or primary key

The upserts target ['projectId', 'qfRoundId'], but ProjectQfRound is defined with a composite primary key on (id, projectId, qfRoundId) and no unique index on (projectId, qfRoundId). Add @Unique(['projectId', 'qfRoundId']) in src/entities/projectQfRound.ts (or adjust the PK) so the conflict target aligns with a unique constraint.

🤖 Prompt for AI Agents
In src/repositories/projectRepository.test.ts around lines 1172-1190 the test
upserts use ['projectId','qfRoundId'] as the conflict target but the
ProjectQfRound entity defines a composite primary key on (id, projectId,
qfRoundId) with no unique index on (projectId, qfRoundId); update
src/entities/projectQfRound.ts to add @Unique(['projectId','qfRoundId']) on the
entity (or alternatively change the primary key to the composite (projectId,
qfRoundId)) so the upsert conflict columns match an actual unique constraint.


// Test sorting by ActiveQfRoundRaisedFunds
const [sortedProjects] = await findQfRoundProjects(qfRound.id, {
Expand Down
Loading