Add fit info to homepage

I wasn't sure how to fill the space for items that are fully modeled, then realized some basic at-a-glance "who does this fit" would help!

The load time isn't great, I think I need to break out that dependent subquery, but maybe the stale-while-revalidate will cover it well enough at first.
This commit is contained in:
Emi Matchu 2021-07-11 19:08:47 -07:00
parent 2a5ecb688a
commit af493f6719
3 changed files with 96 additions and 23 deletions

View file

@ -385,6 +385,24 @@ function NewItemsSectionContent() {
id id
name name
} }
compatibleBodiesAndTheirZones {
body {
id
representsAllBodies
species {
id
name
}
canonicalAppearance {
id
color {
id
name
isStandard
}
}
}
}
} }
} }
` `
@ -478,9 +496,46 @@ function ItemModelingSummary({ item }) {
); );
} }
const bodies = item.compatibleBodiesAndTheirZones.map((bz) => bz.body);
const fitsAllPets = bodies.some((b) => b.representsAllBodies);
if (fitsAllPets) {
return ( return (
<Box fontSize="xs" fontStyle="italic" opacity="0.8"> <Box fontSize="xs" fontStyle="italic" opacity="0.8">
Fully modeled! For all pets
</Box>
);
}
const colors = bodies.map((b) => b.canonicalAppearance.color);
const specialColor = colors.find((c) => !c.isStandard);
if (specialColor && bodies.length === 1) {
return (
<Box fontSize="xs" fontStyle="italic" opacity="0.8">
{specialColor.name} {bodies[0].species.name} only
</Box>
);
}
if (bodies.length === 1) {
return (
<Box fontSize="xs" fontStyle="italic" opacity="0.8">
{bodies[0].species.name} only
</Box>
);
}
if (specialColor) {
return (
<Box fontSize="xs" fontStyle="italic" opacity="0.8">
{specialColor.name} only
</Box>
);
}
return (
<Box fontSize="xs" fontStyle="italic" opacity="0.8">
For all species
</Box> </Box>
); );
} }

View file

@ -657,6 +657,37 @@ const buildItemAllOccupiedZonesLoader = (db) =>
}); });
}); });
const buildItemCompatibleBodiesAndTheirZonesLoader = (db) =>
new DataLoader(async (itemIds) => {
const qs = itemIds.map((_) => "?").join(", ");
const [rows] = await db.query(
`
SELECT
items.id as itemId,
swf_assets.body_id AS bodyId,
(SELECT species_id FROM pet_types WHERE body_id = bodyId LIMIT 1)
AS speciesId,
GROUP_CONCAT(DISTINCT swf_assets.zone_id) AS zoneIds
FROM items
INNER JOIN parents_swf_assets ON
items.id = parents_swf_assets.parent_id AND
parents_swf_assets.parent_type = "Item"
INNER JOIN swf_assets ON
parents_swf_assets.swf_asset_id = swf_assets.id
WHERE items.id IN (${qs})
GROUP BY items.id, swf_assets.body_id
-- We have some invalid data where the asset has a body ID that
-- matches no pet type. Huh! Well, ignore those bodies!
HAVING speciesId IS NOT NULL OR bodyId = 0;
`,
itemIds
);
const entities = rows.map(normalizeRow);
return itemIds.map((itemId) => entities.filter((e) => e.itemId === itemId));
});
const buildItemTradesLoader = (db, loaders) => const buildItemTradesLoader = (db, loaders) =>
new DataLoader( new DataLoader(
async (itemIdOwnedPairs) => { async (itemIdOwnedPairs) => {
@ -1368,6 +1399,9 @@ function buildLoaders(db) {
db db
); );
loaders.itemAllOccupiedZonesLoader = buildItemAllOccupiedZonesLoader(db); loaders.itemAllOccupiedZonesLoader = buildItemAllOccupiedZonesLoader(db);
loaders.itemCompatibleBodiesAndTheirZonesLoader = buildItemCompatibleBodiesAndTheirZonesLoader(
db
);
loaders.itemTradesLoader = buildItemTradesLoader(db, loaders); loaders.itemTradesLoader = buildItemTradesLoader(db, loaders);
loaders.itemWakaValueLoader = buildItemWakaValueLoader(); loaders.itemWakaValueLoader = buildItemWakaValueLoader();
loaders.petTypeLoader = buildPetTypeLoader(db, loaders); loaders.petTypeLoader = buildPetTypeLoader(db, loaders);

View file

@ -559,28 +559,12 @@ const resolvers = {
const bodies = bodyIds.map((id) => ({ id })); const bodies = bodyIds.map((id) => ({ id }));
return bodies; return bodies;
}, },
compatibleBodiesAndTheirZones: async ({ id }, _, { db }) => { compatibleBodiesAndTheirZones: async (
const [rows] = await db.query( { id },
` _,
SELECT { itemCompatibleBodiesAndTheirZonesLoader }
swf_assets.body_id AS bodyId, ) => {
(SELECT species_id FROM pet_types WHERE body_id = bodyId LIMIT 1) const rows = await itemCompatibleBodiesAndTheirZonesLoader.load(id);
AS speciesId,
GROUP_CONCAT(DISTINCT swf_assets.zone_id) AS zoneIds
FROM items
INNER JOIN parents_swf_assets ON
items.id = parents_swf_assets.parent_id AND
parents_swf_assets.parent_type = "Item"
INNER JOIN swf_assets ON
parents_swf_assets.swf_asset_id = swf_assets.id
WHERE items.id = ?
GROUP BY swf_assets.body_id
-- We have some invalid data where the asset has a body ID that
-- matches no pet type. Huh! Well, ignore those bodies!
HAVING speciesId IS NOT NULL OR bodyId = 0;
`,
[id]
);
return rows.map((row) => ({ return rows.map((row) => ({
body: { body: {
id: row.bodyId, id: row.bodyId,