From 45ffa92f1da8149570aaa0d592a17bd400d60473 Mon Sep 17 00:00:00 2001 From: Matchu Date: Fri, 11 Sep 2020 21:34:28 -0700 Subject: [PATCH] add itemsTheyWant to user GQL --- src/app/ItemsPage.js | 25 +++++ src/server/loaders.js | 6 +- src/server/query-tests/User.test.js | 138 +++++++++++++++++++++++++++- src/server/types/User.js | 56 +++++++++-- 4 files changed, 212 insertions(+), 13 deletions(-) diff --git a/src/app/ItemsPage.js b/src/app/ItemsPage.js index d8c508a..d6e101c 100644 --- a/src/app/ItemsPage.js +++ b/src/app/ItemsPage.js @@ -24,12 +24,20 @@ function ItemsPage() { user(id: $userId) { id username + itemsTheyOwn { id isNc name thumbnailUrl } + + itemsTheyWant { + id + isNc + name + thumbnailUrl + } } } `, @@ -66,6 +74,23 @@ function ItemsPage() { /> ))} + + + {isCurrentUser ? "Items you want" : `Items ${data.user.username} wants`} + + + {data.user.itemsTheyWant.map((item) => ( + + {item.isNc ? : } + + } + /> + ))} + ); } diff --git a/src/server/loaders.js b/src/server/loaders.js index 7c1bce4..471de7a 100644 --- a/src/server/loaders.js +++ b/src/server/loaders.js @@ -488,7 +488,7 @@ const buildUserLoader = (db) => ); }); -const buildUserOwnedClosetHangersLoader = (db) => +const buildUserClosetHangersLoader = (db) => new DataLoader(async (userIds) => { const qs = userIds.map((_) => "?").join(","); const [rows, _] = await db.execute( @@ -496,7 +496,7 @@ const buildUserOwnedClosetHangersLoader = (db) => INNER JOIN items ON items.id = closet_hangers.item_id INNER JOIN item_translations ON item_translations.item_id = items.id AND locale = "en" - WHERE user_id IN (${qs}) AND owned = 1 + WHERE user_id IN (${qs}) ORDER BY item_name`, userIds ); @@ -604,7 +604,7 @@ function buildLoaders(db) { loaders.speciesLoader = buildSpeciesLoader(db); loaders.speciesTranslationLoader = buildSpeciesTranslationLoader(db); loaders.userLoader = buildUserLoader(db); - loaders.userOwnedClosetHangersLoader = buildUserOwnedClosetHangersLoader(db); + loaders.userClosetHangersLoader = buildUserClosetHangersLoader(db); loaders.userClosetListsLoader = buildUserClosetListsLoader(db); loaders.zoneLoader = buildZoneLoader(db); loaders.zoneTranslationLoader = buildZoneTranslationLoader(db); diff --git a/src/server/query-tests/User.test.js b/src/server/query-tests/User.test.js index 48c91f7..a248a60 100644 --- a/src/server/query-tests/User.test.js +++ b/src/server/query-tests/User.test.js @@ -178,7 +178,7 @@ describe("User", () => { INNER JOIN items ON items.id = closet_hangers.item_id INNER JOIN item_translations ON item_translations.item_id = items.id AND locale = \\"en\\" - WHERE user_id IN (?) AND owned = 1 + WHERE user_id IN (?) ORDER BY item_name", Array [ "44743", @@ -240,7 +240,141 @@ describe("User", () => { INNER JOIN items ON items.id = closet_hangers.item_id INNER JOIN item_translations ON item_translations.item_id = items.id AND locale = \\"en\\" - WHERE user_id IN (?) AND owned = 1 + WHERE user_id IN (?) + ORDER BY item_name", + Array [ + "44743", + ], + ], + Array [ + "SELECT * FROM closet_lists + WHERE user_id IN (?) + ORDER BY name", + Array [ + "44743", + ], + ], + ] + `); + }); + + it("gets private items they want for current user", async () => { + await logInAsTestUser(); + + const res = await query({ + query: gql` + query { + user(id: "44743") { + id + username + itemsTheyWant { + id + name + } + } + } + `, + }); + + expect(res).toHaveNoErrors(); + expect(res.data).toMatchInlineSnapshot(` + Object { + "user": Object { + "id": "44743", + "itemsTheyWant": Array [ + Object { + "id": "39945", + "name": "Altador Cup Background - Haunted Woods", + }, + Object { + "id": "39956", + "name": "Altador Cup Background - Kreludor", + }, + Object { + "id": "39947", + "name": "Altador Cup Background - Shenkuu", + }, + ], + "username": "dti-test", + }, + } + `); + expect(getDbCalls()).toMatchInlineSnapshot(` + Array [ + Array [ + "SELECT * FROM users WHERE id IN (?)", + Array [ + "44743", + ], + ], + Array [ + "SELECT closet_hangers.*, item_translations.name as item_name FROM closet_hangers + INNER JOIN items ON items.id = closet_hangers.item_id + INNER JOIN item_translations ON + item_translations.item_id = items.id AND locale = \\"en\\" + WHERE user_id IN (?) + ORDER BY item_name", + Array [ + "44743", + ], + ], + Array [ + "SELECT * FROM closet_lists + WHERE user_id IN (?) + ORDER BY name", + Array [ + "44743", + ], + ], + ] + `); + }); + + it("hides private items they want from other users", async () => { + const res = await query({ + query: gql` + query { + user(id: "44743") { + id + username + itemsTheyWant { + id + name + } + } + } + `, + }); + + expect(res).toHaveNoErrors(); + expect(res.data).toMatchInlineSnapshot(` + Object { + "user": Object { + "id": "44743", + "itemsTheyWant": Array [ + Object { + "id": "39947", + "name": "Altador Cup Background - Shenkuu", + }, + ], + "username": "dti-test", + }, + } + `); + expect(getDbCalls()).toMatchInlineSnapshot(` + Array [ + Array [ + "SELECT * FROM users WHERE id IN (?)", + Array [ + "44743", + ], + ], + Array [ + "SELECT closet_hangers.*, item_translations.name as item_name FROM closet_hangers + INNER JOIN items ON items.id = closet_hangers.item_id + INNER JOIN item_translations ON + item_translations.item_id = items.id AND locale = \\"en\\" + WHERE user_id IN (?) ORDER BY item_name", Array [ "44743", diff --git a/src/server/types/User.js b/src/server/types/User.js index 5f05803..dc16286 100644 --- a/src/server/types/User.js +++ b/src/server/types/User.js @@ -5,6 +5,7 @@ const typeDefs = gql` id: ID! username: String! itemsTheyOwn: [Item!]! + itemsTheyWant: [Item!]! } extend type Query { @@ -19,6 +20,7 @@ const resolvers = { const user = await userLoader.load(id); return user.name; }, + itemsTheyOwn: async ( { id }, _, @@ -26,23 +28,61 @@ const resolvers = { currentUserId, userClosetListsLoader, userLoader, - userOwnedClosetHangersLoader, + userClosetHangersLoader, } ) => { const [allClosetHangers, closetLists, user] = await Promise.all([ - userOwnedClosetHangersLoader.load(id), + userClosetHangersLoader.load(id), userClosetListsLoader.load(id), userLoader.load(id), ]); const closetListsById = new Map(closetLists.map((l) => [l.id, l])); - const visibleClosetHangers = allClosetHangers.filter( - (h) => - user.id === currentUserId || - (h.listId == null && user.ownedClosetHangersVisibility >= 1) || - (h.listId != null && closetListsById.get(h.listId).visibility >= 1) - ); + const visibleClosetHangers = allClosetHangers + .filter((h) => h.owned) + .filter( + (h) => + user.id === currentUserId || + (h.listId == null && user.ownedClosetHangersVisibility >= 1) || + (h.listId != null && closetListsById.get(h.listId).visibility >= 1) + ); + + const items = visibleClosetHangers.map((h) => ({ + id: h.itemId, + // We get this for the ORDER BY clause anyway - may as well include it + // here to avoid an extra lookup! + name: h.itemName, + })); + return items; + }, + + itemsTheyWant: async ( + { id }, + _, + { + currentUserId, + userClosetListsLoader, + userLoader, + userClosetHangersLoader, + } + ) => { + const [allClosetHangers, closetLists, user] = await Promise.all([ + userClosetHangersLoader.load(id), + userClosetListsLoader.load(id), + userLoader.load(id), + ]); + + const closetListsById = new Map(closetLists.map((l) => [l.id, l])); + + const visibleClosetHangers = allClosetHangers + .filter((h) => !h.owned) + .filter( + (h) => + user.id === currentUserId || + (h.listId == null && user.wantedClosetHangersVisibility >= 1) || + (h.listId != null && closetListsById.get(h.listId).visibility >= 1) + ); const items = visibleClosetHangers.map((h) => ({ id: h.itemId,