add id to ItemAppearance (+ refactor)

This is in support of a caching issue in a hack tool coming next! Without this, the change to ItemAppearance restricted zones would make other ItemAppearance fields go missing (bc our hack tool didn't also specify them), so the query would re-execute over the network to find the missing fields we overwrote with nothingness—which would undo the local hack change.
This commit is contained in:
Emi Matchu 2020-08-28 00:10:00 -07:00
parent a58db2dcd1
commit 17fa9d06b9
4 changed files with 50 additions and 46 deletions

View file

@ -116,6 +116,7 @@ export function getVisibleLayers(petAppearance, itemAppearances) {
export const itemAppearanceFragment = gql` export const itemAppearanceFragment = gql`
fragment ItemAppearanceForOutfitPreview on ItemAppearance { fragment ItemAppearanceForOutfitPreview on ItemAppearance {
id
layers { layers {
id id
remoteId # HACK: This is for Support tools, but other views don't need it remoteId # HACK: This is for Support tools, but other views don't need it
@ -129,7 +130,6 @@ export const itemAppearanceFragment = gql`
label @client # HACK: This is for Support tools, but other views don't need it label @client # HACK: This is for Support tools, but other views don't need it
} }
} }
restrictedZones { restrictedZones {
id id
} }

View file

@ -71,7 +71,10 @@ const typeDefs = gql`
thumbnailUrl: String! thumbnailUrl: String!
rarityIndex: Int! rarityIndex: Int!
isNc: Boolean! isNc: Boolean!
appearanceOn(speciesId: ID!, colorId: ID!): ItemAppearance
# How this item appears on the given species/color combo. If it does not
# fit the pet, we'll return an empty ItemAppearance with no layers.
appearanceOn(speciesId: ID!, colorId: ID!): ItemAppearance!
# This is set manually by Support users, when the pet is only for e.g. # This is set manually by Support users, when the pet is only for e.g.
# Maraquan pets, and our usual auto-detection isn't working. We provide # Maraquan pets, and our usual auto-detection isn't working. We provide
@ -101,7 +104,10 @@ const typeDefs = gql`
} }
type ItemAppearance { type ItemAppearance {
layers: [AppearanceLayer!]! id: ID!
item: Item!
bodyId: ID!
layers: [AppearanceLayer!]
restrictedZones: [Zone!]! restrictedZones: [Zone!]!
} }
@ -275,37 +281,13 @@ const resolvers = {
appearanceOn: async ( appearanceOn: async (
{ id }, { id },
{ speciesId, colorId }, { speciesId, colorId },
{ petTypeBySpeciesAndColorLoader, itemSwfAssetLoader, itemLoader } { petTypeBySpeciesAndColorLoader }
) => { ) => {
const itemPromise = itemLoader.load(id);
const petType = await petTypeBySpeciesAndColorLoader.load({ const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId: speciesId, speciesId,
colorId: colorId, colorId,
}); });
const allSwfAssets = await itemSwfAssetLoader.load({ return { item: { id }, bodyId: petType.bodyId };
itemId: id,
bodyId: petType.bodyId,
});
if (allSwfAssets.length === 0) {
// If there's no assets at all, treat it as non-fitting: no appearance.
// (If there are assets but they're non-SWF, we'll treat this as
// fitting, but with an *empty* appearance.)
return null;
}
const swfAssets = allSwfAssets.filter((sa) => sa.url.endsWith(".swf"));
const restrictedZones = [];
const item = await itemPromise;
for (const [i, bit] of Array.from(item.zonesRestrict).entries()) {
if (bit === "1") {
const zone = { id: i + 1 };
restrictedZones.push(zone);
}
}
return { layers: swfAssets, restrictedZones };
}, },
manualSpecialColor: async ({ id }, _, { itemLoader }) => { manualSpecialColor: async ({ id }, _, { itemLoader }) => {
const item = await itemLoader.load(id); const item = await itemLoader.load(id);
@ -318,6 +300,28 @@ const resolvers = {
return item.explicitlyBodySpecific; return item.explicitlyBodySpecific;
}, },
}, },
ItemAppearance: {
id: ({ item, bodyId }) => `item-${item.id}-body-${bodyId}`,
layers: async ({ item, bodyId }, _, { itemSwfAssetLoader }) => {
const allSwfAssets = await itemSwfAssetLoader.load({
itemId: item.id,
bodyId,
});
return allSwfAssets.filter((sa) => sa.url.endsWith(".swf"));
},
restrictedZones: async ({ item: { id: itemId } }, _, { itemLoader }) => {
const item = await itemLoader.load(itemId);
const restrictedZones = [];
for (const [i, bit] of Array.from(item.zonesRestrict).entries()) {
if (bit === "1") {
const zone = { id: i + 1 };
restrictedZones.push(zone);
}
}
return restrictedZones;
},
},
PetAppearance: { PetAppearance: {
color: async ({ id }, _, { petStateLoader, petTypeLoader }) => { color: async ({ id }, _, { petStateLoader, petTypeLoader }) => {
const petState = await petStateLoader.load(id); const petState = await petStateLoader.load(id);

View file

@ -102,14 +102,6 @@ describe("Item", () => {
"37375", "37375",
], ],
], ],
Array [
"SELECT * FROM items WHERE id IN (?,?,?)",
Array [
"38912",
"38911",
"37375",
],
],
Array [ Array [
"SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)", "SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)",
Array [ Array [
@ -132,6 +124,14 @@ describe("Item", () => {
"180", "180",
], ],
], ],
Array [
"SELECT * FROM items WHERE id IN (?,?,?)",
Array [
"38912",
"38911",
"37375",
],
],
Array [ Array [
"SELECT * FROM zones WHERE id IN (?,?,?)", "SELECT * FROM zones WHERE id IN (?,?,?)",
Array [ Array [
@ -191,12 +191,6 @@ describe("Item", () => {
"42829", "42829",
], ],
], ],
Array [
"SELECT * FROM items WHERE id IN (?)",
Array [
"42829",
],
],
Array [ Array [
"SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)", "SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)",
Array [ Array [
@ -215,6 +209,12 @@ describe("Item", () => {
"180", "180",
], ],
], ],
Array [
"SELECT * FROM items WHERE id IN (?)",
Array [
"42829",
],
],
] ]
`); `);
}); });

View file

@ -62,7 +62,7 @@ Object {
"layers": Array [ "layers": Array [
Object { Object {
"id": "30203", "id": "30203",
"imageUrl": "https://impress-asset-images.s3.amazonaws.com/object/000/000/006/6829/600x600.png?v2-0", "imageUrl": "https://impress-asset-images.s3.amazonaws.com/object/000/000/006/6829/600x600.png?v2-1598519675000",
"remoteId": "6829", "remoteId": "6829",
"svgUrl": null, "svgUrl": null,
"zone": Object { "zone": Object {