'Define a prisma schema for twitter's like feed

i'm currently working on a twitter clone with express / prisma / postgreSQL for my backend.

I'm struggling to imitate twitter's feed.

Here's my current prisma Schema

model User {
  id          String    @id @default(cuid())
  email       String    @unique
  username    String    @unique
  profilename String?
  password    String
  bio         String?
  image       String?
  createdAt   DateTime  @default(now())
  isAdmin     Boolean   @default(false)
  tweets      Tweet[]
  retweets    Retweet[]
  likes       Like[]
  followers   Follows[] @relation("follower")
  following   Follows[] @relation("following")
}

model Follows {
  follower    User     @relation("following", fields: [followerId], references: [id])
  followerId  String
  following   User     @relation("follower", fields: [followingId], references: [id])
  followingId String
  createdAt   DateTime @default(now())

  @@id([followerId, followingId])
}

model Tweet {
  id              String    @id @default(cuid())
  content         String
  createdAt       DateTime  @default(now())
  deleted         Boolean   @default(false)
  media           String[]
  author          User      @relation(fields: [authorId], references: [id], onDelete: Cascade)
  authorId        String
  originalTweet   Tweet?    @relation("replies", fields: [originalTweetId], references: [id], onDelete: Cascade)
  originalTweetId String?
  responses       Tweet[]   @relation("replies")
  likes           Like[]
  retweets        Retweet[]
  hashtags        Hashtag[]
}

model Hashtag {
  id        String   @id @default(cuid())
  name      String   @unique
  createdAt DateTime @default(now())
  tweets    Tweet[]
}

model Retweet {
  id        String   @id @default(cuid())
  tweet     Tweet    @relation(fields: [tweetId], references: [id], onDelete: Cascade)
  tweetId   String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId    String
  createdAt DateTime @default(now())

}

model Like {
  id        String   @id @default(cuid())
  tweet     Tweet    @relation(fields: [tweetId], references: [id], onDelete: Cascade)
  tweetId   String
  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId    String
  createdAt DateTime @default(now())
}

and my current function to get user feed

exports.getUserFeed = async (userId, options = {}) => {
  try {
    const user = await prisma.user.findUnique({
      where: { id: userId },
      include: { following: true },
    })

    if (user.following.length === 0) {
      return prisma.tweet.findMany({
        orderBy: {
          createdAt: "desc",
        },
        ...options,
      })
    }

    return prisma.tweet.findMany({
      where: {
        OR: [
          {
            author: {
              followers: {
                some: {
                  followerId: userId,
                },
              },
            },
          },
          {
            likes: {
              some: {
                user: {
                  followers: {
                    some: {
                      followerId: userId,
                    },
                  },
                },
              },
            },
          },
          {
            retweets: {
              some: {
                user: {
                  followers: {
                    some: {
                      followerId: userId,
                    },
                  },
                },
              },
            },
          },
        ],
      },
      orderBy: {
        createdAt: "desc",
      },
      ...options,
    })
  } catch (err) {
    throw new Error(err)
  }
}

With this i get tweets posted by user i follow, liked by user i follow and retweeted by user i follow but order by tweet's created at not by the "event" created at.

To solve this i thought about creating a new model called Event or Status with optionnal feed like:

  • isRetweet ?
  • isLike ?
  • etc

and then retrieve this instead of tweet model.

But it seems messy and complex for no reason. Is there a way to actually define a better schema or do a better query ?

Thanks a lot.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source