feat: implement user follow system

This commit is contained in:
Aaron William Po
2023-11-12 17:32:43 -05:00
parent d48d9a8886
commit 24e245fc6f
5 changed files with 88 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
-- CreateTable
CREATE TABLE "UserFollow" (
"followerId" TEXT NOT NULL,
"followingId" TEXT NOT NULL,
"followedAt" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "UserFollow_pkey" PRIMARY KEY ("followerId","followingId")
);
-- AddForeignKey
ALTER TABLE "UserFollow" ADD CONSTRAINT "UserFollow_followerId_fkey" FOREIGN KEY ("followerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "UserFollow" ADD CONSTRAINT "UserFollow_followingId_fkey" FOREIGN KEY ("followingId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@@ -44,6 +44,18 @@ model User {
beerStyleLikes BeerStyleLike[]
beerStyleComments BeerStyleComment[]
userAvatar UserAvatar?
followedBy UserFollow[] @relation("following")
following UserFollow[] @relation("follower")
}
model UserFollow {
follower User @relation("follower", fields: [followerId], references: [id])
followerId String
following User @relation("following", fields: [followingId], references: [id])
followingId String
followedAt DateTime @default(now()) @db.Timestamptz(3)
@@id([followerId, followingId])
}
model UserAvatar {

View File

@@ -0,0 +1,54 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { faker } from '@faker-js/faker';
import type { User } from '@prisma/client';
import DBClient from '../../DBClient';
interface CreateNewUserFollowsArgs {
joinData: { users: User[] };
}
interface UserFollowData {
followerId: string;
followingId: string;
followedAt: Date;
}
const createNewUserFollows = async ({
joinData: { users },
}: CreateNewUserFollowsArgs) => {
const userFollows: UserFollowData[] = [];
users.forEach((user) => {
// Get 20 random users to follow.
const randomUsers = users
.filter((randomUser) => randomUser.id !== user.id)
.sort(() => Math.random() - Math.random())
.slice(0, 20);
// Get the user to follow the random users, and the random users to follow the user.
const data = randomUsers.flatMap((randomUser) => [
{
followerId: user.id,
followingId: randomUser.id,
followedAt: faker.date.between({ from: user.createdAt, to: new Date() }),
},
{
followerId: randomUser.id,
followingId: user.id,
followedAt: faker.date.between({ from: randomUser.createdAt, to: new Date() }),
},
]);
userFollows.push(...data);
});
await DBClient.instance.userFollow.createMany({
data: userFollows,
skipDuplicates: true,
});
return DBClient.instance.userFollow.findMany();
};
export default createNewUserFollows;

View File

@@ -18,6 +18,7 @@ interface UserData {
hash: string;
accountIsVerified: boolean;
role: 'USER' | 'ADMIN';
bio: string;
}
const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
@@ -54,6 +55,7 @@ const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
const dateOfBirth = faker.date.birthdate({ mode: 'age', min: 19 });
const createdAt = faker.date.past({ years: 4 });
const bio = faker.lorem.paragraphs(3).replace(/\n/g, ' ');
const user: UserData = {
firstName,
@@ -63,6 +65,7 @@ const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
dateOfBirth,
createdAt,
hash,
bio,
accountIsVerified: true,
role: 'USER',
};

View File

@@ -19,6 +19,7 @@ import createAdminUser from './create/createAdminUser';
import createNewBeerStyleComments from './create/createNewBeerStyleComments';
import createNewBeerStyleLikes from './create/createNewBeerStyleLikes';
import createNewUserAvatars from './create/createNewUserAvatars';
import createNewUserFollows from './create/createNewUserFollows';
(async () => {
try {
@@ -37,6 +38,9 @@ import createNewUserAvatars from './create/createNewUserAvatars';
const userAvatars = await createNewUserAvatars({ joinData: { users } });
logger.info('User avatars created successfully.');
const userFollows = await createNewUserFollows({ joinData: { users } });
logger.info('User follows created successfully.');
const locations = await createNewLocations({
numberOfLocations: 500,
joinData: { users },
@@ -108,6 +112,7 @@ import createNewUserAvatars from './create/createNewUserAvatars';
logger.info({
numberOfUsers: users.length,
numberOfUserAvatars: userAvatars.length,
numberOfUserFollows: userFollows.length,
numberOfBreweryPosts: breweryPosts.length,
numberOfBeerPosts: beerPosts.length,
numberOfBeerStyles: beerStyles.length,