Skip to content

Commit 4ad1f89

Browse files
committed
Merge remote-tracking branch 'origin/main' into release
2 parents 88eb4db + dc75067 commit 4ad1f89

3 files changed

Lines changed: 106 additions & 11 deletions

File tree

src/api/controllers/ChatController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ export class ChatController {
232232

233233
try {
234234
const result = await queryRunner.query(`
235-
INSERT INTO "Transaction" (location, amount, completed, post_id, buyer_id, seller_id, "transactionDate", "confirmationSent")
235+
INSERT INTO "Transaction" (location, amount, completed, "postId", "buyerId", "sellerId", "transactionDate", "confirmationSent")
236236
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
237237
RETURNING id
238238
`, ["", amount, false, post.id, buyer.firebaseUid, seller.firebaseUid, transactionDate, false]);

src/repositories/PostRepository.ts

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -509,23 +509,69 @@ export class PostRepository extends AbstractRepository<PostModel> {
509509
.getOne();
510510
}
511511

512+
/**
513+
* Fallback when no embedding-similar posts exist: returns other active posts
514+
* (excluding this post, and excluding same user). Ordered by newest first.
515+
*/
516+
public async getSimilarPostsFallback(
517+
excludePostId: string,
518+
excludeUserId: string,
519+
limit: number,
520+
): Promise<PostModel[]> {
521+
return await this.repository
522+
.createQueryBuilder("post")
523+
.leftJoinAndSelect("post.user", "user")
524+
.where("post.id != :excludePostId", { excludePostId })
525+
.andWhere("post.archive = false")
526+
.andWhere("post.sold = false")
527+
.andWhere("user.firebaseUid != :excludeUserId", { excludeUserId })
528+
.orderBy("post.created", "DESC")
529+
.limit(limit)
530+
.getMany();
531+
}
532+
533+
/**
534+
* Fallback when even getSimilarPostsFallback is empty (e.g. only one user has posts):
535+
* returns other active posts by any user, excluding only this post.
536+
*/
537+
public async getSimilarPostsFallbackIncludeSameUser(
538+
excludePostId: string,
539+
limit: number,
540+
): Promise<PostModel[]> {
541+
return await this.repository
542+
.createQueryBuilder("post")
543+
.leftJoinAndSelect("post.user", "user")
544+
.where("post.id != :excludePostId", { excludePostId })
545+
.andWhere("post.archive = false")
546+
.andWhere("post.sold = false")
547+
.orderBy("post.created", "DESC")
548+
.limit(limit)
549+
.getMany();
550+
}
551+
512552
/*
513553
This method is for getting similar posts for a given post query embedding.
554+
Only returns active, non-archived, unsold posts with embeddings.
555+
Fetches extra candidates so that after filtering (inactive users, blocked users)
556+
we still have at least a few results.
514557
*/
515558
public async getSimilarPosts(
516559
queryEmbedding: number[],
517560
excludePostId: string,
518561
excludeUserId: string,
562+
limit = 20,
519563
): Promise<PostModel[]> {
520564
const lit = `[${queryEmbedding.join(",")}]`;
521565
return await this.repository
522566
.createQueryBuilder("post")
523567
.leftJoinAndSelect("post.user", "user")
524568
.where("post.id != :excludePostId", { excludePostId })
569+
.andWhere("post.embedding IS NOT NULL")
570+
.andWhere("post.archive = false")
571+
.andWhere("post.sold = false")
525572
.andWhere("user.firebaseUid != :excludeUserId", { excludeUserId })
526-
.orderBy(`embedding::vector <-> CAST('${lit}' AS vector(512))`)
527-
.setParameters({ embedding: queryEmbedding })
528-
.limit(10)
573+
.orderBy(`post.embedding::vector <-> CAST('${lit}' AS vector(512))`)
574+
.limit(limit)
529575
.getMany();
530576
}
531577

src/services/PostService.ts

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -570,22 +570,71 @@ export class PostService {
570570
});
571571
}
572572

573+
/**
574+
* Returns the 4 closest similar posts by embedding (active, unsold only).
575+
* If no similar posts (e.g. few posts, or only current user's posts), returns
576+
* up to 4 other active posts as a fallback so the UI isn't empty.
577+
*/
573578
public async similarPosts(
574579
user: UserModel,
575580
params: UuidParam,
576581
): Promise<PostModel[]> {
582+
const SIMILAR_COUNT = 4;
577583
return this.transactions.readOnly(async (transactionalEntityManager) => {
578584
const postRepository = Repositories.post(transactionalEntityManager);
579585
const post = await postRepository.getPostById(params.id);
580-
if (!post) throw new NotFoundError('Post not found!');
581-
582-
// Posts with no embeddings cant have similar posts, so return empty array
583-
if (post.embedding == null) {
584-
return [];
586+
if (!post) throw new NotFoundError("Post not found!");
587+
const embedding = post.embedding;
588+
589+
if (embedding == null) {
590+
let fallback = await postRepository.getSimilarPostsFallback(
591+
post.id,
592+
user.firebaseUid,
593+
SIMILAR_COUNT,
594+
);
595+
if (fallback.length === 0) {
596+
fallback = await postRepository.getSimilarPostsFallbackIncludeSameUser(
597+
post.id,
598+
SIMILAR_COUNT,
599+
);
600+
}
601+
const active = this.filterInactiveUserPosts(fallback);
602+
return (await this.filterBlockedUserPosts(active, user)).slice(
603+
0,
604+
SIMILAR_COUNT,
605+
);
585606
}
586-
const similarPosts = await postRepository.getSimilarPosts(post.embedding, post.id, user.firebaseUid);
607+
608+
const similarPosts = await postRepository.getSimilarPosts(
609+
embedding,
610+
post.id,
611+
user.firebaseUid,
612+
20,
613+
);
587614
const activePosts = this.filterInactiveUserPosts(similarPosts);
588-
return this.filterBlockedUserPosts(activePosts, user);
615+
const filtered = await this.filterBlockedUserPosts(activePosts, user);
616+
const result = filtered.slice(0, SIMILAR_COUNT);
617+
618+
if (result.length === 0) {
619+
let fallback = await postRepository.getSimilarPostsFallback(
620+
post.id,
621+
user.firebaseUid,
622+
SIMILAR_COUNT,
623+
);
624+
if (fallback.length === 0) {
625+
fallback = await postRepository.getSimilarPostsFallbackIncludeSameUser(
626+
post.id,
627+
SIMILAR_COUNT,
628+
);
629+
}
630+
const active = this.filterInactiveUserPosts(fallback);
631+
return (await this.filterBlockedUserPosts(active, user)).slice(
632+
0,
633+
SIMILAR_COUNT,
634+
);
635+
}
636+
637+
return result;
589638
});
590639
}
591640

0 commit comments

Comments
 (0)