GraphQL for user's itemsTheyOwn
This commit is contained in:
parent
df49e08bff
commit
e2b5486168
4 changed files with 158 additions and 8 deletions
|
@ -19,6 +19,7 @@ GRANT UPDATE ON openneo_impress.pet_states TO impress2020;
|
|||
GRANT UPDATE ON openneo_impress.swf_assets TO impress2020;
|
||||
|
||||
-- User data tables
|
||||
GRANT SELECT ON openneo_impress.closet_hangers TO impress2020;
|
||||
GRANT SELECT ON openneo_impress.item_outfit_relationships TO impress2020;
|
||||
GRANT SELECT ON openneo_impress.outfits TO impress2020;
|
||||
GRANT SELECT ON openneo_impress.users TO impress2020;
|
||||
|
|
|
@ -229,6 +229,7 @@ const typeDefs = gql`
|
|||
type User {
|
||||
id: ID!
|
||||
username: String!
|
||||
itemsTheyOwn: [Item!]!
|
||||
}
|
||||
|
||||
type Query {
|
||||
|
@ -622,13 +623,38 @@ const resolvers = {
|
|||
const user = await userLoader.load(id);
|
||||
return user.name;
|
||||
},
|
||||
itemsTheyOwn: async (
|
||||
{ id },
|
||||
_,
|
||||
{ currentUserId, userLoader, userOwnedClosetHangersLoader }
|
||||
) => {
|
||||
const user = await userLoader.load(id);
|
||||
const hangersAreVisible =
|
||||
user.ownedClosetHangersVisibility >= 2 || user.id === currentUserId;
|
||||
if (!hangersAreVisible) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const allClosetHangers = await userOwnedClosetHangersLoader.load(id);
|
||||
const closetHangersWithNoList = allClosetHangers.filter(
|
||||
(h) => h.listId == null
|
||||
);
|
||||
|
||||
const items = closetHangersWithNoList.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;
|
||||
},
|
||||
},
|
||||
Query: {
|
||||
allColors: async (_, { ids }, { colorLoader }) => {
|
||||
allColors: async (_, __, { colorLoader }) => {
|
||||
const allColors = await colorLoader.loadAll();
|
||||
return allColors;
|
||||
},
|
||||
allSpecies: async (_, { ids }, { speciesLoader }) => {
|
||||
allSpecies: async (_, __, { speciesLoader }) => {
|
||||
const allSpecies = await speciesLoader.loadAll();
|
||||
return allSpecies;
|
||||
},
|
||||
|
@ -708,7 +734,7 @@ const resolvers = {
|
|||
outfit: (_, { id }) => ({ id }),
|
||||
user: async (_, { id }, { userLoader }) => {
|
||||
try {
|
||||
const user = await userLoader.load(id);
|
||||
await userLoader.load(id);
|
||||
} catch (e) {
|
||||
if (e.message.includes("could not find user")) {
|
||||
return null;
|
||||
|
@ -725,7 +751,7 @@ const resolvers = {
|
|||
}
|
||||
|
||||
try {
|
||||
const user = await userLoader.load(currentUserId);
|
||||
await userLoader.load(currentUserId);
|
||||
} catch (e) {
|
||||
if (e.message.includes("could not find user")) {
|
||||
return null;
|
||||
|
|
|
@ -425,8 +425,9 @@ const buildPetStatesForPetTypeLoader = (db, loaders) =>
|
|||
);
|
||||
});
|
||||
|
||||
const buildUserLoader = (db) => new DataLoader(async (ids) => {
|
||||
const qs = ids.map((_) => "?").join(",");
|
||||
const buildUserLoader = (db) =>
|
||||
new DataLoader(async (ids) => {
|
||||
const qs = ids.map((_) => "?").join(",");
|
||||
const [rows, _] = await db.execute(
|
||||
`SELECT * FROM users WHERE id IN (${qs})`,
|
||||
ids
|
||||
|
@ -440,7 +441,26 @@ const buildUserLoader = (db) => new DataLoader(async (ids) => {
|
|||
entitiesById.get(String(id)) ||
|
||||
new Error(`could not find user with ID: ${id}`)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const buildUserOwnedClosetHangersLoader = (db) =>
|
||||
new DataLoader(async (userIds) => {
|
||||
const qs = userIds.map((_) => "?").join(",");
|
||||
const [rows, _] = await db.execute(
|
||||
`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 (${qs}) AND owned = 1
|
||||
ORDER BY item_name`,
|
||||
userIds
|
||||
);
|
||||
const entities = rows.map(normalizeRow);
|
||||
|
||||
return userIds.map((userId) =>
|
||||
entities.filter((e) => e.userId === String(userId))
|
||||
);
|
||||
});
|
||||
|
||||
const buildZoneLoader = (db) => {
|
||||
const zoneLoader = new DataLoader(async (ids) => {
|
||||
|
@ -522,6 +542,7 @@ function buildLoaders(db) {
|
|||
loaders.speciesLoader = buildSpeciesLoader(db);
|
||||
loaders.speciesTranslationLoader = buildSpeciesTranslationLoader(db);
|
||||
loaders.userLoader = buildUserLoader(db);
|
||||
loaders.userOwnedClosetHangersLoader = buildUserOwnedClosetHangersLoader(db);
|
||||
loaders.zoneLoader = buildZoneLoader(db);
|
||||
loaders.zoneTranslationLoader = buildZoneTranslationLoader(db);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ const { query, getDbCalls, logInAsTestUser } = require("./setup.js");
|
|||
describe("User", () => {
|
||||
it("looks up a user", async () => {
|
||||
// TODO: I'm not sure why this is taking extra time, maybe the db conn?
|
||||
jest.setTimeout(10000);
|
||||
jest.setTimeout(20000);
|
||||
|
||||
const res = await query({
|
||||
query: gql`
|
||||
|
@ -115,4 +115,106 @@ describe("User", () => {
|
|||
expect(res.data).toEqual({ currentUser: null });
|
||||
expect(getDbCalls()).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
it("gets private items they own for current user", async () => {
|
||||
await logInAsTestUser();
|
||||
|
||||
const res = await query({
|
||||
query: gql`
|
||||
query {
|
||||
user(id: "44743") {
|
||||
id
|
||||
username
|
||||
itemsTheyOwn {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
expect(res).toHaveNoErrors();
|
||||
expect(res.data).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"user": Object {
|
||||
"id": "44743",
|
||||
"itemsTheyOwn": Array [
|
||||
Object {
|
||||
"id": "74967",
|
||||
"name": "17th Birthday Party Hat",
|
||||
},
|
||||
Object {
|
||||
"id": "49026",
|
||||
"name": "Abominable Snowman Hat",
|
||||
},
|
||||
Object {
|
||||
"id": "40319",
|
||||
"name": "Blue Jelly Tiara",
|
||||
},
|
||||
],
|
||||
"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 (44743) AND owned = 1
|
||||
ORDER BY item_name",
|
||||
Array [
|
||||
"44743",
|
||||
],
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it("hides private items they own from other users", async () => {
|
||||
const res = await query({
|
||||
query: gql`
|
||||
query {
|
||||
user(id: "44743") {
|
||||
id
|
||||
username
|
||||
itemsTheyOwn {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
expect(res).toHaveNoErrors();
|
||||
expect(res.data).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"user": Object {
|
||||
"id": "44743",
|
||||
"itemsTheyOwn": Array [],
|
||||
"username": "dti-test",
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(getDbCalls()).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"SELECT * FROM users WHERE id IN (?)",
|
||||
Array [
|
||||
"44743",
|
||||
],
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue