From eb67d86163fc54bc015fbb049ef6cc25a50cfdd0 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 29 Aug 2017 18:57:20 +0700 Subject: [PATCH] Implement UserConnection on the graph --- graph/loaders/users.js | 42 ++++++++++++++++++++++++++++++++--------- graph/resolvers/user.js | 5 +++-- graph/typeDefs.graphql | 18 +++++++++++++++++- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/graph/loaders/users.js b/graph/loaders/users.js index 999ad1938..3d48bafd7 100644 --- a/graph/loaders/users.js +++ b/graph/loaders/users.js @@ -26,12 +26,12 @@ const genUserByIDs = async (context, ids) => { * @param {Object} context graph context * @param {Object} query query terms to apply to the users query */ -const getUsersByQuery = ({user}, {ids, limit, cursor, statuses = null, sortOrder}) => { +const getUsersByQuery = async ({user}, {ids, limit, cursor, statuses = null, sortOrder}) => { - let users = UserModel.find(); + let query = UserModel.find(); if (ids) { - users = users.find({ + query = query.find({ id: { $in: ids } @@ -39,7 +39,7 @@ const getUsersByQuery = ({user}, {ids, limit, cursor, statuses = null, sortOrder } if (statuses != null) { - users = users.where({ + query = query.where({ status: { $in: statuses } @@ -48,13 +48,13 @@ const getUsersByQuery = ({user}, {ids, limit, cursor, statuses = null, sortOrder if (cursor) { if (sortOrder === 'DESC') { - users = users.where({ + query = query.where({ created_at: { $lt: cursor } }); } else { - users = users.where({ + query = query.where({ created_at: { $gt: cursor } @@ -62,9 +62,33 @@ const getUsersByQuery = ({user}, {ids, limit, cursor, statuses = null, sortOrder } } - return users - .sort({created_at: sortOrder === 'DESC' ? -1 : 1}) - .limit(limit); + // Apply the limit. + if (limit) { + query = query.limit(limit + 1); + } + + const nodes = await query.exec(); + + // The hasNextPage is always handled the same (ask for one more than we need, + // if there is one more, than there is more). + let hasNextPage = false; + if (limit && nodes.length > limit) { + + // There was one more than we expected! Set hasNextPage = true and remove + // the last item from the array that we requested. + hasNextPage = true; + nodes.splice(limit, 1); + } + + const startCursor = nodes.length ? nodes[0].created_at : null; + const endCursor = nodes.length ? nodes[nodes.length - 1].created_at : null; + + return { + startCursor, + endCursor, + hasNextPage, + nodes, + }; }; /** diff --git a/graph/resolvers/user.js b/graph/resolvers/user.js index 57601c269..e5c5746ca 100644 --- a/graph/resolvers/user.js +++ b/graph/resolvers/user.js @@ -51,7 +51,7 @@ const User = { return tokens; }, - ignoredUsers({id}, args, {user, loaders: {Users}}) { + async ignoredUsers({id}, args, {user, loaders: {Users}}) { // Only allow a logged in user that is either the current user or is a staff // member to access the ignoredUsers of a given user. @@ -64,7 +64,8 @@ const User = { return []; } - return Users.getByQuery({ids: user.ignoresUsers}); + const connection = await Users.getByQuery({ids: user.ignoresUsers}); + return connection.nodes; }, roles({id, roles}, _, {user}) { diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index 4dff623fd..5bebb7e76 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -121,6 +121,22 @@ type User { suspension: SuspensionInfo } +# UserConnection represents a paginable subset of a user list. +type UserConnection { + + # Indicates that there are more users after this subset. + hasNextPage: Boolean! + + # Cursor of first user in subset. + startCursor: Cursor + + # Cursor of last user in subset. + endCursor: Cursor + + # Subset of users. + nodes: [User!]! +} + # UsersQuery allows the ability to query users by a specific fields. input UsersQuery { action_type: ACTION_TYPE @@ -731,7 +747,7 @@ type RootQuery { me: User # Users returned based on a query. - users(query: UsersQuery): [User] + users(query: UsersQuery!): UserConnection # a single User by id user(id: ID!): User