Skip to content

Commit f831679

Browse files
authored
Merge pull request #10 from aseerkt/feat/followers
Feature Follow Backend Code
2 parents ee72de8 + 2453dcc commit f831679

File tree

5 files changed

+125
-52
lines changed

5 files changed

+125
-52
lines changed

client/src/routes/Explore.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import { Post, useGetExplorePostsQuery } from '../generated/graphql';
77

88
const Explore = () => {
99
const [observedPost, setObservedPost] = useState('');
10-
const { data, loading, error, fetchMore, variables, networkStatus } =
10+
const { data, loading, error, fetchMore, variables } =
1111
useGetExplorePostsQuery({
1212
variables: { limit: 12 },
13-
notifyOnNetworkStatusChange: true,
1413
});
1514

1615
useEffect(() => {
@@ -59,7 +58,6 @@ const Explore = () => {
5958
{data?.getExplorePosts.posts && (
6059
<PostsGrid posts={data.getExplorePosts.posts as Post[]} />
6160
)}
62-
{networkStatus === 7 && <Spinner />}
6361
</Container>
6462
);
6563
};

client/src/routes/Posts.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ import { Link } from 'react-router-dom';
99

1010
const Posts: React.FC = () => {
1111
const [observedPost, setObservedPost] = React.useState('');
12-
const { data, loading, error, fetchMore, variables, networkStatus } =
13-
useGetPostsQuery({
14-
variables: { limit: 4 },
15-
notifyOnNetworkStatusChange: true,
16-
});
12+
const { data, loading, error, fetchMore, variables } = useGetPostsQuery({
13+
variables: { limit: 4 },
14+
});
1715

1816
React.useEffect(() => {
1917
if (data) {
@@ -66,7 +64,6 @@ const Posts: React.FC = () => {
6664
{data.getPosts.posts.map((post) => (
6765
<PostCard key={post.id} post={post as Post} />
6866
))}
69-
{networkStatus === 7 && <Spinner />}
7067
</div>
7168
<div className='relative flex-1 hidden md:block md:ml-4'>
7269
{data && data.getPosts.posts.length > 0 && <ProfileRight />}

server/src/resolvers/CommentResolver.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,11 @@ export class CommentResolver {
3737
@Ctx() { res }: MyContext
3838
) {
3939
try {
40-
const comment = await Comment.create({
40+
return await Comment.create({
4141
postId,
4242
text,
4343
username: res.locals.username,
4444
}).save();
45-
return comment;
4645
} catch (err) {
4746
console.log(err);
4847
return false;

server/src/resolvers/FollowerResolver.ts

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ID,
55
Mutation,
66
Query,
7+
registerEnumType,
78
Resolver,
89
UseMiddleware,
910
} from 'type-graphql';
@@ -13,8 +14,89 @@ import { User } from '../entities/User';
1314
import { isAuth } from '../middlewares/isAuth';
1415
import { MyContext } from '../types';
1516

17+
enum FollowEnum {
18+
Followers,
19+
Followings,
20+
}
21+
22+
registerEnumType(FollowEnum, { name: 'FollowEnum' });
23+
1624
@Resolver()
1725
export class FollowerResolver {
26+
// QUERIES
27+
28+
@Query(() => [User])
29+
@UseMiddleware(isAuth)
30+
async getFollowSuggestions(@Ctx() { res }: MyContext): Promise<User[]> {
31+
const suggestions = await getConnection().query(
32+
`
33+
SELECT
34+
"u"."id",
35+
"u"."username",
36+
"u"."email",
37+
"u"."createdAt",
38+
"u"."updatedAt"
39+
FROM "users" "u"
40+
LEFT JOIN "follows" "f"
41+
ON "f"."followingUsername" = "u"."username"
42+
WHERE ("f"."username" != $1 OR "f"."username" IS NULL) AND "u"."username" != $1
43+
LIMIT 5;
44+
`,
45+
[res.locals.username]
46+
);
47+
48+
// "f"."followingUsername" != "u"."username"
49+
50+
return suggestions;
51+
}
52+
53+
@Query(() => [User])
54+
@UseMiddleware(isAuth)
55+
async getFollows(
56+
@Arg('username') username: string,
57+
@Arg('selector', () => FollowEnum) selector: FollowEnum
58+
) {
59+
if (selector === FollowEnum.Followers) {
60+
const followers = await getConnection().query(
61+
`
62+
SELECT
63+
"u"."id",
64+
"u"."username",
65+
"u"."email",
66+
"u"."createdAt",
67+
"u"."updatedAt"
68+
FROM "users" "u"
69+
LEFT JOIN "follows" "f"
70+
ON "f"."username" = "u"."username"
71+
WHERE "f"."followingUsername" = $1
72+
LIMIT 10
73+
`,
74+
[username]
75+
);
76+
return followers;
77+
} else {
78+
const followings = await getConnection().query(
79+
`
80+
SELECT
81+
"u"."id",
82+
"u"."username",
83+
"u"."email",
84+
"u"."createdAt",
85+
"u"."updatedAt"
86+
FROM "users" "u"
87+
LEFT JOIN "follows" "f"
88+
ON "f"."followingUsername" = "u"."username"
89+
WHERE "f"."username" = $1
90+
LIMIT 10
91+
`,
92+
[username]
93+
);
94+
return followings;
95+
}
96+
}
97+
98+
// MUTATIONS
99+
18100
@Mutation(() => Boolean)
19101
@UseMiddleware(isAuth)
20102
async toggleFollow(
@@ -39,29 +121,4 @@ export class FollowerResolver {
39121
return false;
40122
}
41123
}
42-
43-
@Query(() => [User])
44-
@UseMiddleware(isAuth)
45-
async getFollowSuggestions(@Ctx() { res }: MyContext): Promise<User[]> {
46-
const suggestions = await getConnection().query(
47-
`
48-
SELECT
49-
"u"."id",
50-
"u"."username",
51-
"u"."email",
52-
"u"."createdAt",
53-
"u"."updatedAt"
54-
FROM "users" "u"
55-
LEFT JOIN "follows" "f"
56-
ON "f"."followingUsername" = "u"."username"
57-
WHERE "u"."username" != $1
58-
LIMIT 5
59-
`,
60-
[res.locals.username]
61-
);
62-
63-
// "f"."followingUsername" != "u"."username"
64-
65-
return suggestions;
66-
}
67124
}

server/src/resolvers/PostResolver.ts

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
Root,
1515
UseMiddleware,
1616
} from 'type-graphql';
17+
import { getConnection } from 'typeorm';
1718
import { CLOUDINARY_ROOT_PATH, __prod__ } from '../constants';
1819
import { Comment } from '../entities/Comment';
1920
import { Like } from '../entities/Like';
@@ -85,36 +86,55 @@ export class PostResolver {
8586
@Query(() => PaginatedPost)
8687
@UseMiddleware(isAuth)
8788
async getPosts(
89+
@Ctx() { res }: MyContext,
90+
@Arg('limit', () => Int) limit: number,
91+
@Arg('offset', () => Int, { nullable: true }) offset?: number
92+
): Promise<PaginatedPost> {
93+
const params = [res.locals.username, limit + 1];
94+
if (offset) params.push(offset);
95+
// Get posts from followed peoples only
96+
const posts: Post[] = await getConnection().query(
97+
`
98+
SELECT
99+
"p"."id",
100+
"p"."createdAt",
101+
"p"."updatedAt",
102+
"p"."caption",
103+
"p"."imgURL",
104+
"p"."username"
105+
FROM "posts" "p"
106+
LEFT JOIN "follows" "f"
107+
ON "f"."followingUsername" = "p"."username"
108+
WHERE "f"."username" = $1
109+
ORDER BY "p"."createdAt" DESC
110+
LIMIT $2 ${offset ? 'OFFSET $3' : ''};
111+
`,
112+
params
113+
);
114+
return {
115+
posts: posts.slice(0, limit),
116+
hasMore: posts.length === limit + 1,
117+
};
118+
}
119+
120+
@Query(() => PaginatedPost)
121+
@UseMiddleware(isAuth)
122+
async getExplorePosts(
88123
@Arg('limit', () => Int) limit: number,
89124
@Arg('offset', () => Int, { nullable: true }) offset?: number
90125
): Promise<PaginatedPost> {
91-
// TODO: Pagination
92126
const posts = await Post.find({
93127
order: { createdAt: 'DESC' },
94128
skip: offset ? offset : 0,
95129
take: limit + 1,
96130
});
131+
97132
return {
98133
posts: posts.slice(0, limit),
99134
hasMore: posts.length === limit + 1,
100135
};
101136
}
102137

103-
// @Query(() => [Post])
104-
// @UseMiddleware(isAuth)
105-
// async getFeedPosts(@Ctx() { res }: MyContext) {
106-
// const followings = await Follow.find({
107-
// where: { username: res.locals.username },
108-
// select: ['following'],
109-
// relations: ['following.posts'],
110-
// });
111-
// const feedPosts: Post[] = [];
112-
// followings.forEach((f) => {
113-
// feedPosts.push(...f.following.posts);
114-
// });
115-
// return feedPosts;
116-
// }
117-
118138
@Query(() => Post, { nullable: true })
119139
@UseMiddleware(isAuth)
120140
getSinglePost(@Arg('postId') postId: string) {
@@ -196,3 +216,5 @@ export class PostResolver {
196216
* curl 'http://localhost:5000/graphql' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: http://localhost:5000' --data-binary '{"query":"mutation AddPost($file: Upload!){\n addPost(file)\n}"}' --compressed
197217
*
198218
*/
219+
220+
// SELECT "p"."id", "p"."createdAt", "p"."updatedAt", "p"."caption", "p"."imgURL", "p"."username" FROM "posts" "p" LEFT JOIN "follows" "f" ON "f"."followingUsername" = "p"."username" WHERE "f"."username" = 'bob' ORDER BY "p"."createdAt" DESC LIMIT 6 OFFSET 10;

0 commit comments

Comments
 (0)