refactor Outfit.js to split Pet to a separate type

yeah, I had unified Pet into Outfit, but now I think that was overly clever… 😅

Here, I define a new Pet type, and it has some of the fields of Outfit and the deprecated fields still.

I did this because I want petAppearance to work, for UC testing!
This commit is contained in:
Emi Matchu 2020-09-27 03:18:46 -07:00
parent 94f6363251
commit e57af14625
2 changed files with 61 additions and 24 deletions

View file

@ -324,7 +324,7 @@ const buildItemBodiesWithAppearanceDataLoader = (db) =>
return itemIds.map((itemId) => entities.filter((e) => e.itemId === itemId)); return itemIds.map((itemId) => entities.filter((e) => e.itemId === itemId));
}); });
const buildPetTypeLoader = (db) => const buildPetTypeLoader = (db, loaders) =>
new DataLoader(async (petTypeIds) => { new DataLoader(async (petTypeIds) => {
const qs = petTypeIds.map((_) => "?").join(","); const qs = petTypeIds.map((_) => "?").join(",");
const [rows, _] = await db.execute( const [rows, _] = await db.execute(
@ -334,6 +334,13 @@ const buildPetTypeLoader = (db) =>
const entities = rows.map(normalizeRow); const entities = rows.map(normalizeRow);
for (const petType of entities) {
loaders.petTypeBySpeciesAndColorLoader.prime(
{ speciesId: petType.speciesId, colorId: petType.colorId },
petType
);
}
return petTypeIds.map((petTypeId) => return petTypeIds.map((petTypeId) =>
entities.find((e) => e.id === petTypeId) entities.find((e) => e.id === petTypeId)
); );
@ -577,7 +584,7 @@ const buildCanonicalPetStateForBodyLoader = (db, loaders) =>
); );
}); });
const buildPetStateByPetTypeAndAssetsLoader = (db) => const buildPetStateByPetTypeAndAssetsLoader = (db, loaders) =>
new DataLoader( new DataLoader(
async (petTypeIdAndAssetIdsPairs) => { async (petTypeIdAndAssetIdsPairs) => {
const qs = petTypeIdAndAssetIdsPairs const qs = petTypeIdAndAssetIdsPairs
@ -593,6 +600,10 @@ const buildPetStateByPetTypeAndAssetsLoader = (db) =>
const entities = rows.map(normalizeRow); const entities = rows.map(normalizeRow);
for (const petState of entities) {
loaders.petStateLoader.prime(petState.id, petState);
}
return petTypeIdAndAssetIdsPairs.map(({ petTypeId, swfAssetIds }) => return petTypeIdAndAssetIdsPairs.map(({ petTypeId, swfAssetIds }) =>
entities.find( entities.find(
(e) => e.petTypeId === petTypeId && e.swfAssetIds === swfAssetIds (e) => e.petTypeId === petTypeId && e.swfAssetIds === swfAssetIds
@ -721,7 +732,7 @@ function buildLoaders(db) {
loaders.itemBodiesWithAppearanceDataLoader = buildItemBodiesWithAppearanceDataLoader( loaders.itemBodiesWithAppearanceDataLoader = buildItemBodiesWithAppearanceDataLoader(
db db
); );
loaders.petTypeLoader = buildPetTypeLoader(db); loaders.petTypeLoader = buildPetTypeLoader(db, loaders);
loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader( loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader(
db, db,
loaders loaders
@ -744,7 +755,8 @@ function buildLoaders(db) {
loaders loaders
); );
loaders.petStateByPetTypeAndAssetsLoader = buildPetStateByPetTypeAndAssetsLoader( loaders.petStateByPetTypeAndAssetsLoader = buildPetStateByPetTypeAndAssetsLoader(
db db,
loaders
); );
loaders.speciesLoader = buildSpeciesLoader(db); loaders.speciesLoader = buildSpeciesLoader(db);
loaders.speciesTranslationLoader = buildSpeciesTranslationLoader(db); loaders.speciesTranslationLoader = buildSpeciesTranslationLoader(db);

View file

@ -1,5 +1,6 @@
const fetch = require("node-fetch"); const fetch = require("node-fetch");
const { gql } = require("apollo-server"); const { gql } = require("apollo-server");
const { getPoseFromPetState } = require("../util");
const typeDefs = gql` const typeDefs = gql`
type Outfit { type Outfit {
@ -8,6 +9,14 @@ const typeDefs = gql`
petAppearance: PetAppearance! petAppearance: PetAppearance!
wornItems: [Item!]! wornItems: [Item!]!
closetedItems: [Item!]! closetedItems: [Item!]!
}
# TODO: This maybe should move to a separate file?
type Pet {
id: ID!
name: String!
petAppearance: PetAppearance!
wornItems: [Item!]!
species: Species! # to be deprecated? can use petAppearance? 🤔 species: Species! # to be deprecated? can use petAppearance? 🤔
color: Color! # to be deprecated? can use petAppearance? 🤔 color: Color! # to be deprecated? can use petAppearance? 🤔
@ -17,7 +26,7 @@ const typeDefs = gql`
extend type Query { extend type Query {
outfit(id: ID!): Outfit outfit(id: ID!): Outfit
petOnNeopetsDotCom(petName: String!): Outfit petOnNeopetsDotCom(petName: String!): Pet
} }
`; `;
@ -44,6 +53,37 @@ const resolvers = {
.map((oir) => ({ id: oir.itemId })); .map((oir) => ({ id: oir.itemId }));
}, },
}, },
Pet: {
species: ({ customPetData }) => ({
id: customPetData.custom_pet.species_id,
}),
color: ({ customPetData }) => ({ id: customPetData.custom_pet.color_id }),
pose: ({ customPetData, petMetaData }) =>
getPoseFromPetData(petMetaData, customPetData),
petAppearance: async (
{ customPetData, petMetaData },
_,
{ petTypeBySpeciesAndColorLoader, petStatesForPetTypeLoader }
) => {
const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId: customPetData.custom_pet.species_id,
colorId: customPetData.custom_pet.color_id,
});
const petStates = await petStatesForPetTypeLoader.load(petType.id);
const pose = getPoseFromPetData(petMetaData, customPetData);
const petState = petStates.find((ps) => getPoseFromPetState(ps) === pose);
return { id: petState.id };
},
wornItems: ({ customPetData }) =>
Object.values(customPetData.object_info_registry).map((o) => ({
id: o.obj_info_id,
name: o.name,
description: o.description,
thumbnailUrl: o.thumbnail_url,
rarityIndex: o.rarity_index,
})),
items: (...args) => resolvers.Pet.wornItems(...args),
},
Query: { Query: {
outfit: (_, { id }) => ({ id }), outfit: (_, { id }) => ({ id }),
petOnNeopetsDotCom: async ( petOnNeopetsDotCom: async (
@ -72,23 +112,7 @@ const resolvers = {
swfAssetByRemoteIdLoader, swfAssetByRemoteIdLoader,
}); });
const outfit = { return { name, customPetData, petMetaData };
// TODO: This isn't a fully-working Outfit object. It works for the
// client as currently implemented, but we'll probably want to
// move the client and this onto our more generic fields!
species: { id: customPetData.custom_pet.species_id },
color: { id: customPetData.custom_pet.color_id },
pose: getPoseFromPetData(petMetaData, customPetData),
items: Object.values(customPetData.object_info_registry).map((o) => ({
id: o.obj_info_id,
name: o.name,
description: o.description,
thumbnailUrl: o.thumbnail_url,
rarityIndex: o.rarity_index,
})),
};
return outfit;
}, },
}, },
}; };
@ -129,10 +153,11 @@ async function loadCustomPetData(petName) {
} }
function getPoseFromPetData(petMetaData, petCustomData) { function getPoseFromPetData(petMetaData, petCustomData) {
// TODO: Use custom data to decide if Unconverted.
const moodId = petMetaData.mood; const moodId = petMetaData.mood;
const genderId = petMetaData.gender; const genderId = petMetaData.gender;
if (String(moodId) === "1" && String(genderId) === "1") { if (Object.keys(petCustomData.custom_pet.biology_by_zone).length === 1) {
return "UNCONVERTED";
} else if (String(moodId) === "1" && String(genderId) === "1") {
return "HAPPY_MASC"; return "HAPPY_MASC";
} else if (String(moodId) === "1" && String(genderId) === "2") { } else if (String(moodId) === "1" && String(genderId) === "2") {
return "HAPPY_FEM"; return "HAPPY_FEM";