mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
feat: implement user follow system
This commit is contained in:
14
src/prisma/migrations/20231112221155_/migration.sql
Normal file
14
src/prisma/migrations/20231112221155_/migration.sql
Normal 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;
|
||||||
@@ -44,6 +44,18 @@ model User {
|
|||||||
beerStyleLikes BeerStyleLike[]
|
beerStyleLikes BeerStyleLike[]
|
||||||
beerStyleComments BeerStyleComment[]
|
beerStyleComments BeerStyleComment[]
|
||||||
userAvatar UserAvatar?
|
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 {
|
model UserAvatar {
|
||||||
|
|||||||
54
src/prisma/seed/create/createNewUserFollows.ts
Normal file
54
src/prisma/seed/create/createNewUserFollows.ts
Normal 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;
|
||||||
@@ -18,6 +18,7 @@ interface UserData {
|
|||||||
hash: string;
|
hash: string;
|
||||||
accountIsVerified: boolean;
|
accountIsVerified: boolean;
|
||||||
role: 'USER' | 'ADMIN';
|
role: 'USER' | 'ADMIN';
|
||||||
|
bio: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
|
const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
|
||||||
@@ -54,6 +55,7 @@ const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
|
|||||||
|
|
||||||
const dateOfBirth = faker.date.birthdate({ mode: 'age', min: 19 });
|
const dateOfBirth = faker.date.birthdate({ mode: 'age', min: 19 });
|
||||||
const createdAt = faker.date.past({ years: 4 });
|
const createdAt = faker.date.past({ years: 4 });
|
||||||
|
const bio = faker.lorem.paragraphs(3).replace(/\n/g, ' ');
|
||||||
|
|
||||||
const user: UserData = {
|
const user: UserData = {
|
||||||
firstName,
|
firstName,
|
||||||
@@ -63,6 +65,7 @@ const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
|
|||||||
dateOfBirth,
|
dateOfBirth,
|
||||||
createdAt,
|
createdAt,
|
||||||
hash,
|
hash,
|
||||||
|
bio,
|
||||||
accountIsVerified: true,
|
accountIsVerified: true,
|
||||||
role: 'USER',
|
role: 'USER',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import createAdminUser from './create/createAdminUser';
|
|||||||
import createNewBeerStyleComments from './create/createNewBeerStyleComments';
|
import createNewBeerStyleComments from './create/createNewBeerStyleComments';
|
||||||
import createNewBeerStyleLikes from './create/createNewBeerStyleLikes';
|
import createNewBeerStyleLikes from './create/createNewBeerStyleLikes';
|
||||||
import createNewUserAvatars from './create/createNewUserAvatars';
|
import createNewUserAvatars from './create/createNewUserAvatars';
|
||||||
|
import createNewUserFollows from './create/createNewUserFollows';
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -37,6 +38,9 @@ import createNewUserAvatars from './create/createNewUserAvatars';
|
|||||||
const userAvatars = await createNewUserAvatars({ joinData: { users } });
|
const userAvatars = await createNewUserAvatars({ joinData: { users } });
|
||||||
logger.info('User avatars created successfully.');
|
logger.info('User avatars created successfully.');
|
||||||
|
|
||||||
|
const userFollows = await createNewUserFollows({ joinData: { users } });
|
||||||
|
logger.info('User follows created successfully.');
|
||||||
|
|
||||||
const locations = await createNewLocations({
|
const locations = await createNewLocations({
|
||||||
numberOfLocations: 500,
|
numberOfLocations: 500,
|
||||||
joinData: { users },
|
joinData: { users },
|
||||||
@@ -108,6 +112,7 @@ import createNewUserAvatars from './create/createNewUserAvatars';
|
|||||||
logger.info({
|
logger.info({
|
||||||
numberOfUsers: users.length,
|
numberOfUsers: users.length,
|
||||||
numberOfUserAvatars: userAvatars.length,
|
numberOfUserAvatars: userAvatars.length,
|
||||||
|
numberOfUserFollows: userFollows.length,
|
||||||
numberOfBreweryPosts: breweryPosts.length,
|
numberOfBreweryPosts: breweryPosts.length,
|
||||||
numberOfBeerPosts: beerPosts.length,
|
numberOfBeerPosts: beerPosts.length,
|
||||||
numberOfBeerStyles: beerStyles.length,
|
numberOfBeerStyles: beerStyles.length,
|
||||||
|
|||||||
Reference in New Issue
Block a user