diff --git a/src/server/index.js b/src/server/index.js index 463800d..6b71432 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -12,15 +12,47 @@ const typeDefs = gql` SIZE_150 } + """ + A pet's gender presentation: masculine or feminine. + + Neopets calls these "male" and "female", and I think that's silly and not wise + to propagate further, especially in the context of a strictly visual app like + Dress to Impress! This description isn't altogether correct either, but idk + what's better :/ + """ + enum GenderPresentation { + MASCULINE + FEMININE + } + + """ + A pet's emotion: happy, sad, or sick. + + Note that we don't ever show the angry emotion on Dress to Impress, because + we don't have the data: it's impossible for a pet's passive emotion on the + pet lookup to be angry! + """ + enum Emotion { + HAPPY + SAD + SICK + } + type Item { id: ID! name: String! description: String! thumbnailUrl: String! - appearanceOn(speciesId: ID!, colorId: ID!): Appearance + appearanceOn(speciesId: ID!, colorId: ID!): ItemAppearance } - type Appearance { + type PetAppearance { + genderPresentation: GenderPresentation + emotion: Emotion + layers: [AppearanceLayer!]! + } + + type ItemAppearance { layers: [AppearanceLayer!]! restrictedZones: [Zone!]! } @@ -77,7 +109,8 @@ const typeDefs = gql` offset: Int limit: Int ): ItemSearchResult! - petAppearance(speciesId: ID!, colorId: ID!): Appearance + petAppearance(speciesId: ID!, colorId: ID!): PetAppearance + petAppearances(speciesId: ID!, colorId: ID!): [PetAppearance!]! petOnNeopetsDotCom(petName: String!): Outfit } @@ -125,6 +158,40 @@ const resolvers = { return { layers: swfAssets, restrictedZones }; }, }, + PetAppearance: { + genderPresentation: ({ petState }) => { + if (petState.female === 1) { + return "FEMININE"; + } else if (petState.female === 0) { + return "MASCULINE"; + } else if (petState.female === null) { + return null; + } else { + throw new Error( + `unrecognized gender value ${JSON.stringify(petState.female)}` + ); + } + }, + emotion: ({ petState }) => { + if (petState.moodId === "1") { + return "HAPPY"; + } else if (petState.moodId === "2") { + return "SAD"; + } else if (petState.moodId === "4") { + return "SICK"; + } else if (petState.moodId === null) { + return null; + } else { + throw new Error( + `unrecognized moodId ${JSON.stringify(petState.moodId)}` + ); + } + }, + layers: async ({ petState }, _, { petSwfAssetLoader }) => { + const swfAssets = await petSwfAssetLoader.load(petState.id); + return swfAssets; + }, + }, AppearanceLayer: { zone: async (layer, _, { zoneLoader }) => { const zone = await zoneLoader.load(layer.zoneId); @@ -220,9 +287,19 @@ const resolvers = { colorId, }); const petStates = await petStateLoader.load(petType.id); - const petState = petStates[0]; // TODO - const swfAssets = await petSwfAssetLoader.load(petState.id); - return { layers: swfAssets, restrictedZones: [] }; + return { petState: petStates[0] }; + }, + petAppearances: async ( + _, + { speciesId, colorId }, + { petTypeLoader, petStateLoader, petSwfAssetLoader } + ) => { + const petType = await petTypeLoader.load({ + speciesId, + colorId, + }); + const petStates = await petStateLoader.load(petType.id); + return petStates.map((petState) => ({ petState })); }, petOnNeopetsDotCom: async (_, { petName }) => { const petData = await neopets.loadPetData(petName); diff --git a/src/server/loaders.js b/src/server/loaders.js index 2fcfcae..2d30392 100644 --- a/src/server/loaders.js +++ b/src/server/loaders.js @@ -280,7 +280,7 @@ function normalizeRow(row) { const normalizedRow = {}; for (let [key, value] of Object.entries(row)) { key = key.replace(/_([a-z])/gi, (m) => m[1].toUpperCase()); - if (key === "id" || key.endsWith("Id")) { + if ((key === "id" || key.endsWith("Id")) && typeof value === "number") { value = String(value); } normalizedRow[key] = value; diff --git a/src/server/query-tests/PetAppearance.test.js b/src/server/query-tests/PetAppearance.test.js index 3a96a37..5991910 100644 --- a/src/server/query-tests/PetAppearance.test.js +++ b/src/server/query-tests/PetAppearance.test.js @@ -61,4 +61,73 @@ describe("PetAppearance", () => { ] `); }); + + it("loads multiple for species and color", async () => { + const res = await query({ + query: gql` + query { + petAppearances(speciesId: "54", colorId: "75") { + genderPresentation + emotion + layers { + id + imageUrl(size: SIZE_600) + zone { + depth + } + } + } + } + `, + }); + + expect(res).toHaveNoErrors(); + expect(res.data).toMatchSnapshot(); + expect(getDbCalls()).toMatchInlineSnapshot(` + Array [ + Array [ + "SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)", + Array [ + "54", + "75", + ], + ], + Array [ + "SELECT * FROM pet_states WHERE pet_type_id IN (?) + ORDER BY glitched ASC, (mood_id = 1) DESC", + Array [ + "2", + ], + ], + Array [ + "SELECT sa.*, rel.parent_id FROM swf_assets sa + INNER JOIN parents_swf_assets rel ON + rel.parent_type = \\"PetState\\" AND + rel.swf_asset_id = sa.id + WHERE rel.parent_id IN (?,?,?,?,?,?,?,?)", + Array [ + "17723", + "17742", + "10014", + "11089", + "5991", + "436", + "2", + "4751", + ], + ], + Array [ + "SELECT * FROM zones WHERE id IN (?,?,?,?,?,?)", + Array [ + "15", + "5", + "37", + "30", + "33", + "34", + ], + ], + ] + `); + }); }); diff --git a/src/server/query-tests/__snapshots__/PetAppearance.test.js.snap b/src/server/query-tests/__snapshots__/PetAppearance.test.js.snap index 513e838..4733e4f 100644 --- a/src/server/query-tests/__snapshots__/PetAppearance.test.js.snap +++ b/src/server/query-tests/__snapshots__/PetAppearance.test.js.snap @@ -50,3 +50,408 @@ Object { }, } `; + +exports[`PetAppearance loads multiple for species and color 1`] = ` +Object { + "petAppearances": Array [ + Object { + "emotion": "HAPPY", + "genderPresentation": "FEMININE", + "layers": Array [ + Object { + "id": "5995", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7941/600x600.png?v2-0", + "zone": Object { + "depth": 18, + }, + }, + Object { + "id": "5996", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7942/600x600.png?v2-0", + "zone": Object { + "depth": 7, + }, + }, + Object { + "id": "6000", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7946/600x600.png?v2-0", + "zone": Object { + "depth": 40, + }, + }, + Object { + "id": "16467", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/024/24008/600x600.png?v2-0", + "zone": Object { + "depth": 34, + }, + }, + Object { + "id": "19784", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/028/28892/600x600.png?v2-1313418652000", + "zone": Object { + "depth": 37, + }, + }, + Object { + "id": "178150", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/036/36887/600x600.png?v2-1354240708000", + "zone": Object { + "depth": 38, + }, + }, + ], + }, + Object { + "emotion": "HAPPY", + "genderPresentation": "MASCULINE", + "layers": Array [ + Object { + "id": "5995", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7941/600x600.png?v2-0", + "zone": Object { + "depth": 18, + }, + }, + Object { + "id": "5996", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7942/600x600.png?v2-0", + "zone": Object { + "depth": 7, + }, + }, + Object { + "id": "6000", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7946/600x600.png?v2-0", + "zone": Object { + "depth": 40, + }, + }, + Object { + "id": "16467", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/024/24008/600x600.png?v2-0", + "zone": Object { + "depth": 34, + }, + }, + Object { + "id": "19549", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/028/28548/600x600.png?v2-1345719457000", + "zone": Object { + "depth": 37, + }, + }, + Object { + "id": "178150", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/036/36887/600x600.png?v2-1354240708000", + "zone": Object { + "depth": 38, + }, + }, + ], + }, + Object { + "emotion": "SICK", + "genderPresentation": "FEMININE", + "layers": Array [ + Object { + "id": "5995", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7941/600x600.png?v2-0", + "zone": Object { + "depth": 18, + }, + }, + Object { + "id": "5996", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7942/600x600.png?v2-0", + "zone": Object { + "depth": 7, + }, + }, + Object { + "id": "6000", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7946/600x600.png?v2-0", + "zone": Object { + "depth": 40, + }, + }, + Object { + "id": "14791", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/021/21059/600x600.png?v2-0", + "zone": Object { + "depth": 38, + }, + }, + Object { + "id": "14795", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/021/21066/600x600.png?v2-0", + "zone": Object { + "depth": 37, + }, + }, + Object { + "id": "16467", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/024/24008/600x600.png?v2-0", + "zone": Object { + "depth": 34, + }, + }, + ], + }, + Object { + "emotion": "SICK", + "genderPresentation": "MASCULINE", + "layers": Array [ + Object { + "id": "5995", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7941/600x600.png?v2-0", + "zone": Object { + "depth": 18, + }, + }, + Object { + "id": "5996", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7942/600x600.png?v2-0", + "zone": Object { + "depth": 7, + }, + }, + Object { + "id": "6000", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7946/600x600.png?v2-0", + "zone": Object { + "depth": 40, + }, + }, + Object { + "id": "14791", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/021/21059/600x600.png?v2-0", + "zone": Object { + "depth": 38, + }, + }, + Object { + "id": "14794", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/021/21064/600x600.png?v2-0", + "zone": Object { + "depth": 37, + }, + }, + Object { + "id": "16467", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/024/24008/600x600.png?v2-0", + "zone": Object { + "depth": 34, + }, + }, + ], + }, + Object { + "emotion": "SAD", + "genderPresentation": "FEMININE", + "layers": Array [ + Object { + "id": "5995", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7941/600x600.png?v2-0", + "zone": Object { + "depth": 18, + }, + }, + Object { + "id": "5996", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7942/600x600.png?v2-0", + "zone": Object { + "depth": 7, + }, + }, + Object { + "id": "6000", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7946/600x600.png?v2-0", + "zone": Object { + "depth": 40, + }, + }, + Object { + "id": "14790", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/021/21057/600x600.png?v2-0", + "zone": Object { + "depth": 38, + }, + }, + Object { + "id": "14793", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/021/21061/600x600.png?v2-0", + "zone": Object { + "depth": 37, + }, + }, + Object { + "id": "16467", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/024/24008/600x600.png?v2-0", + "zone": Object { + "depth": 34, + }, + }, + ], + }, + Object { + "emotion": "SAD", + "genderPresentation": "MASCULINE", + "layers": Array [ + Object { + "id": "5995", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7941/600x600.png?v2-0", + "zone": Object { + "depth": 18, + }, + }, + Object { + "id": "5996", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7942/600x600.png?v2-0", + "zone": Object { + "depth": 7, + }, + }, + Object { + "id": "6000", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7946/600x600.png?v2-0", + "zone": Object { + "depth": 40, + }, + }, + Object { + "id": "14790", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/021/21057/600x600.png?v2-0", + "zone": Object { + "depth": 38, + }, + }, + Object { + "id": "14792", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/021/21060/600x600.png?v2-0", + "zone": Object { + "depth": 37, + }, + }, + Object { + "id": "16467", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/024/24008/600x600.png?v2-0", + "zone": Object { + "depth": 34, + }, + }, + ], + }, + Object { + "emotion": null, + "genderPresentation": null, + "layers": Array [ + Object { + "id": "5995", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7941/600x600.png?v2-0", + "zone": Object { + "depth": 18, + }, + }, + Object { + "id": "5996", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7942/600x600.png?v2-0", + "zone": Object { + "depth": 7, + }, + }, + Object { + "id": "6000", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7946/600x600.png?v2-0", + "zone": Object { + "depth": 40, + }, + }, + Object { + "id": "16467", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/024/24008/600x600.png?v2-0", + "zone": Object { + "depth": 34, + }, + }, + Object { + "id": "19549", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/028/28548/600x600.png?v2-1345719457000", + "zone": Object { + "depth": 37, + }, + }, + Object { + "id": "19550", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/028/28549/600x600.png?v2-0", + "zone": Object { + "depth": 38, + }, + }, + Object { + "id": "163528", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/028/28549/600x600.png?v2-1326455337000", + "zone": Object { + "depth": 38, + }, + }, + ], + }, + Object { + "emotion": null, + "genderPresentation": null, + "layers": Array [ + Object { + "id": "5995", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7941/600x600.png?v2-0", + "zone": Object { + "depth": 18, + }, + }, + Object { + "id": "5996", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7942/600x600.png?v2-0", + "zone": Object { + "depth": 7, + }, + }, + Object { + "id": "6000", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/007/7946/600x600.png?v2-0", + "zone": Object { + "depth": 40, + }, + }, + Object { + "id": "16467", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/024/24008/600x600.png?v2-0", + "zone": Object { + "depth": 34, + }, + }, + Object { + "id": "19550", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/028/28549/600x600.png?v2-0", + "zone": Object { + "depth": 38, + }, + }, + Object { + "id": "19784", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/028/28892/600x600.png?v2-1313418652000", + "zone": Object { + "depth": 37, + }, + }, + Object { + "id": "163528", + "imageUrl": "https://impress-asset-images.s3.amazonaws.com/biology/000/000/028/28549/600x600.png?v2-1326455337000", + "zone": Object { + "depth": 38, + }, + }, + ], + }, + ], +} +`; diff --git a/src/server/query-tests/__snapshots__/SpeciesColorPair.test.js.snap b/src/server/query-tests/__snapshots__/SpeciesColorPair.test.js.snap index 3557663..928c7e2 100644 --- a/src/server/query-tests/__snapshots__/SpeciesColorPair.test.js.snap +++ b/src/server/query-tests/__snapshots__/SpeciesColorPair.test.js.snap @@ -5035,6 +5035,14 @@ Object { "id": "9", }, }, + Object { + "color": Object { + "id": "105", + }, + "species": Object { + "id": "9", + }, + }, Object { "color": Object { "id": "108", @@ -13923,6 +13931,14 @@ Object { "id": "27", }, }, + Object { + "color": Object { + "id": "17", + }, + "species": Object { + "id": "27", + }, + }, Object { "color": Object { "id": "18",