wasp/examples/realworld/ext/article/queries.js

116 lines
3.9 KiB
JavaScript
Raw Normal View History

import HttpError from '@wasp/core/HttpError.js'
import { userPublicSelection } from '../user/queries.js'
2020-11-27 18:10:02 +03:00
2020-11-27 00:48:35 +03:00
// TODO: I extracted this articleInclude and articleSetFavoritedFields to enable
// reusing of logic that shapes articles as they come out of the server,
// but I wonder if there is a more elegant way - here there are a lot of assumptions,
// and it is easy to not use where it should be used or use it in a wrong setting.
2020-11-27 00:48:35 +03:00
const articleInclude = {
user: {
// TODO: Tricky, if you forget this you could return unwanted fields
// like hashed password!
// It would be cool if we had some protection against making this mistake easily.
select: userPublicSelection
},
2020-11-27 16:25:47 +03:00
tags: true,
2020-11-27 00:48:35 +03:00
favoritedBy: {
select: {
// TODO: Tricky, if I forgot this select here, sensitive data could leak out (hashed password).
username: true
}
}
}
const articleSetFavoritedFields = (article, user) => {
article.favorited = user && article.favoritedBy.find(f => f.username === user.username)
article.favoritesCount = article.favoritedBy.length
delete article.favoritedBy
}
2020-11-28 00:52:38 +03:00
const getArticles = async (queryArgs, context) => {
2020-11-20 20:22:49 +03:00
// TODO: Do some error handling?
const articles = await context.entities.Article.findMany({
2020-11-28 00:52:38 +03:00
...queryArgs,
2020-11-27 00:48:35 +03:00
include: articleInclude
2020-11-20 20:22:49 +03:00
})
2020-11-27 00:48:35 +03:00
for (const article of articles) {
articleSetFavoritedFields(article, context.user)
}
2020-11-20 20:22:49 +03:00
return articles
}
export const getArticlesByUser = async ({ username, skip, take }, context) => {
const where = { user: { username } }
const articles = await getArticles({ where, skip, take }, context)
const count = await context.entities.Article.count({ where })
return { articles, count }
2020-11-27 00:48:35 +03:00
}
export const getFavoritedArticles = async ({ username, skip, take }, context) => {
2020-11-27 00:48:35 +03:00
if (!context.user) { throw new HttpError(403) }
const where = { favoritedBy: { some: { username: context.user.username } } }
const articles = await getArticles({ where, skip, take }, context)
const count = await context.entities.Article.count({ where })
return { articles, count }
2020-11-27 00:48:35 +03:00
}
export const getFollowedArticles = async ({ skip, take }, context) => {
if (!context.user) { throw new HttpError(403) }
const followedUsersIds = (await context.entities.User.findUnique({
where: { id: context.user.id },
include: { following: { select: { id: true } } }
})).following.map(({ id }) => id)
const where = { user: { id: { in: followedUsersIds } } }
const articles = await getArticles({ where, skip, take }, context)
const count = await context.entities.Article.count({ where })
return { articles, count }
}
2020-11-28 00:52:38 +03:00
export const getAllArticles = async ({ skip, take }, context) => {
const articles = await getArticles({ skip, take }, context)
const count = await context.entities.Article.count()
return { articles, count }
}
2020-11-24 23:10:26 +03:00
export const getArticle = async ({ slug }, context) => {
2020-11-20 20:22:49 +03:00
// TODO: Do some error handling?
2020-11-27 00:48:35 +03:00
const article = await context.entities.Article.findUnique({
where: { slug },
include: articleInclude
})
articleSetFavoritedFields(article, context.user)
2020-11-20 20:22:49 +03:00
return article
}
2020-11-25 00:57:14 +03:00
export const getArticleComments = async ({ slug }, context) => {
// TODO: Do some error handling?
const comments = await context.entities.Comment.findMany({
where: { article: { slug } },
include: {
user: {
// TODO: Tricky, if you forget this you could return unwanted fields
// like hashed password!
// It would be cool if we had some protection against making this mistake easily.
select: userPublicSelection
}
}
})
return comments
}
export const getTags = async (_args, context) => {
const tags = await context.entities.ArticleTag.findMany()
// NOTE: This is expensive!
// Consider using a time-limited cache or do some other trick to make it less expensive.
for (const tag of tags) {
tag.numArticles = await context.entities.Article.count({ where: { tags: { some: { name: tag.name }}}})
}
return tags
}