return user from follow/unfollow mutation

This commit is contained in:
Vasily Belolapotkov 2019-09-18 09:49:59 +03:00
parent eeee5f8e9b
commit 7d048b029d
3 changed files with 61 additions and 62 deletions

View File

@ -1,51 +1,44 @@
import { neode as getNeode } from '../../bootstrap/neo4j'
const neode = getNeode()
export default {
Mutation: {
follow: async (_object, params, context, _resolveInfo) => {
const { id, type } = params
const { id: followedId, type } = params
const { user: currentUser } = context
const session = context.driver.session()
const transactionRes = await session.run(
`MATCH (node {id: $id}), (user:User {id: $userId})
WHERE $type IN labels(node) AND NOT $id = $userId
MERGE (user)-[relation:FOLLOWS]->(node)
RETURN COUNT(relation) > 0 as isFollowed`,
{
id,
type,
userId: context.user.id,
},
)
if (type === 'User' && currentUser.id === followedId) {
return null
}
const [isFollowed] = transactionRes.records.map(record => {
return record.get('isFollowed')
})
session.close()
return isFollowed
const [user, followedNode] = await Promise.all([
neode.find('User', currentUser.id),
neode.find(type, followedId),
])
await user.relateTo(followedNode, 'following')
return followedNode.toJson()
},
unfollow: async (_object, params, context, _resolveInfo) => {
const { id, type } = params
const session = context.driver.session()
const { id: followedId, type } = params
const { user: currentUser } = context
const transactionRes = await session.run(
`MATCH (user:User {id: $userId})-[relation:FOLLOWS]->(node {id: $id})
/*
* Note: Neode doesn't provide an easy method for retrieving or removing relationships.
* It's suggested to use query builder feature (https://github.com/adam-cowley/neode/issues/67)
* However, pure cypher query looks cleaner IMO
*/
await neode.cypher(
`MATCH (user:User {id: $currentUser.id})-[relation:FOLLOWS]->(node {id: $followedId})
WHERE $type IN labels(node)
DELETE relation
RETURN COUNT(relation) > 0 as isFollowed`,
{
id,
type,
userId: context.user.id,
},
{ followedId, type, currentUser },
)
const [isFollowed] = transactionRes.records.map(record => {
return record.get('isFollowed')
})
session.close()
return isFollowed
const followedNode = await neode.find(type, followedId)
return followedNode.toJson()
},
},
}

View File

@ -17,13 +17,27 @@ let variables
const mutationFollowUser = gql`
mutation($id: ID!, $type: FollowTypeEnum) {
follow(id: $id, type: $type)
follow(id: $id, type: $type) {
name
followedBy {
id
name
}
followedByCurrentUser
}
}
`
const mutationUnfollowUser = gql`
mutation($id: ID!, $type: FollowTypeEnum) {
unfollow(id: $id, type: $type)
unfollow(id: $id, type: $type) {
name
followedBy {
id
name
}
followedByCurrentUser
}
}
`
@ -58,6 +72,7 @@ beforeEach(async () => {
user1 = await factory
.create('User', {
id: 'u1',
name: 'user1',
email: 'test@example.org',
password: '1234',
})
@ -65,6 +80,7 @@ beforeEach(async () => {
user2 = await factory
.create('User', {
id: 'u2',
name: 'user2',
email: 'test2@example.org',
password: '1234',
})
@ -81,39 +97,34 @@ afterEach(async () => {
describe('follow', () => {
describe('follow user', () => {
describe('unauthenticated follow', () => {
it('throws authorization error', async () => {
test('throws authorization error', async () => {
authenticatedUser = null
const { errors } = await mutate({
const { errors, data } = await mutate({
mutation: mutationFollowUser,
variables,
})
expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
expect(data).toMatchObject({ follow: null })
})
})
it('I can follow another user', async () => {
test('I can follow another user', async () => {
const { data: result } = await mutate({
mutation: mutationFollowUser,
variables,
})
const expectedResult = { follow: true }
expect(result).toMatchObject(expectedResult)
const { data } = await query({
query: userQuery,
variables: { id: user2.id },
})
const expectedUser = {
followedBy: [{ id: user1.id }],
name: user2.name,
followedBy: [{ id: user1.id, name: user1.name }],
followedByCurrentUser: true,
}
expect(data).toMatchObject({ User: [expectedUser] })
expect(result).toMatchObject({ follow: expectedUser })
})
it('I can`t follow myself', async () => {
test('I can`t follow myself', async () => {
variables.id = user1.id
const { data: result } = await mutate({ mutation: mutationFollowUser, variables })
const expectedResult = { follow: false }
const expectedResult = { follow: null }
expect(result).toMatchObject(expectedResult)
const { data } = await query({
@ -137,27 +148,22 @@ describe('follow', () => {
})
describe('unauthenticated follow', () => {
it('throws authorization error', async () => {
test('throws authorization error', async () => {
authenticatedUser = null
const { errors } = await mutate({ mutation: mutationUnfollowUser, variables })
const { errors, data } = await mutate({ mutation: mutationUnfollowUser, variables })
expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
expect(data).toMatchObject({ unfollow: null })
})
})
it('I can unfollow a user', async () => {
const { data: result } = await mutate({ mutation: mutationUnfollowUser, variables })
const expectedResult = { unfollow: true }
expect(result).toMatchObject(expectedResult)
const { data } = await query({
query: userQuery,
variables: { id: user2.id },
})
const expectedUser = {
name: user2.name,
followedBy: [],
followedByCurrentUser: false,
}
expect(data).toMatchObject({ User: [expectedUser] })
expect(result).toMatchObject({ unfollow: expectedUser })
})
})
})

View File

@ -32,9 +32,9 @@ type Mutation {
# Unshout the given Type and ID
unshout(id: ID!, type: ShoutTypeEnum): Boolean!
# Follow the given Type and ID
follow(id: ID!, type: FollowTypeEnum): Boolean!
follow(id: ID!, type: FollowTypeEnum): User
# Unfollow the given Type and ID
unfollow(id: ID!, type: FollowTypeEnum): Boolean!
unfollow(id: ID!, type: FollowTypeEnum): User
}
type Report {