Add support for altStyleId to item search and appearance lookups

I'm not planning to port full Alt Style support over to the 2020
frontend, I really am winding that down, but adding a couple lil API
parameters are *by far* the easiest way to get Alt Styles working in
the main app because of how it calls the 2020 API.

So here we are, adding new API calls but not the frontend changes!
This commit is contained in:
Emi Matchu 2024-02-01 04:59:09 -08:00
parent 505f420d96
commit f566012386
2 changed files with 216 additions and 177 deletions

View file

@ -6,7 +6,7 @@ const buildClosetListLoader = (db) =>
const qs = ids.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM closet_lists WHERE id IN (${qs})`,
ids
ids,
);
const entities = rows.map(normalizeRow);
@ -19,13 +19,13 @@ const buildClosetHangersForListLoader = (db) =>
const qs = closetListIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM closet_hangers WHERE list_id IN (${qs})`,
closetListIds
closetListIds,
);
const entities = rows.map(normalizeRow);
return closetListIds.map((closetListId) =>
entities.filter((e) => e.listId === closetListId)
entities.filter((e) => e.listId === closetListId),
);
});
@ -42,7 +42,7 @@ const buildClosetHangersForDefaultListLoader = (db) =>
.flat();
const [rows] = await db.execute(
`SELECT * FROM closet_hangers WHERE ${conditions}`,
values
values,
);
const entities = rows.map(normalizeRow);
@ -51,8 +51,8 @@ const buildClosetHangersForDefaultListLoader = (db) =>
entities.filter(
(e) =>
e.userId === userId &&
Boolean(e.owned) === (ownsOrWantsItems === "OWNS")
)
Boolean(e.owned) === (ownsOrWantsItems === "OWNS"),
),
);
});
@ -61,7 +61,7 @@ const buildColorLoader = (db) => {
const qs = colorIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM colors WHERE id IN (${qs}) AND prank = 0`,
colorIds
colorIds,
);
const entities = rows.map(normalizeRow);
@ -70,7 +70,7 @@ const buildColorLoader = (db) => {
return colorIds.map(
(colorId) =>
entitiesByColorId.get(String(colorId)) ||
new Error(`could not find color ${colorId}`)
new Error(`could not find color ${colorId}`),
);
});
@ -94,7 +94,7 @@ const buildColorTranslationLoader = (db) =>
const [rows] = await db.execute(
`SELECT * FROM color_translations
WHERE color_id IN (${qs}) AND locale = "en"`,
colorIds
colorIds,
);
const entities = rows.map(normalizeRow);
@ -103,7 +103,7 @@ const buildColorTranslationLoader = (db) =>
return colorIds.map(
(colorId) =>
entitiesByColorId.get(String(colorId)) ||
new Error(`could not find translation for color ${colorId}`)
new Error(`could not find translation for color ${colorId}`),
);
});
@ -112,7 +112,7 @@ const buildSpeciesLoader = (db) => {
const qs = speciesIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM species WHERE id IN (${qs})`,
speciesIds
speciesIds,
);
const entities = rows.map(normalizeRow);
@ -121,7 +121,7 @@ const buildSpeciesLoader = (db) => {
return speciesIds.map(
(speciesId) =>
entitiesBySpeciesId.get(String(speciesId)) ||
new Error(`could not find color ${speciesId}`)
new Error(`could not find color ${speciesId}`),
);
});
@ -145,7 +145,7 @@ const buildSpeciesTranslationLoader = (db) =>
const [rows] = await db.execute(
`SELECT * FROM species_translations
WHERE species_id IN (${qs}) AND locale = "en"`,
speciesIds
speciesIds,
);
const entities = rows.map(normalizeRow);
@ -154,7 +154,7 @@ const buildSpeciesTranslationLoader = (db) =>
return speciesIds.map(
(speciesId) =>
entitiesBySpeciesId.get(String(speciesId)) ||
new Error(`could not find translation for species ${speciesId}`)
new Error(`could not find translation for species ${speciesId}`),
);
});
@ -164,7 +164,7 @@ const buildTradeMatchesLoader = (db) =>
const conditions = userPairs
.map(
(_) =>
`(public_user_hangers.user_id = ? AND current_user_hangers.user_id = ? AND public_user_hangers.owned = ? AND current_user_hangers.owned = ?)`
`(public_user_hangers.user_id = ? AND current_user_hangers.user_id = ? AND public_user_hangers.owned = ? AND current_user_hangers.owned = ?)`,
)
.join(" OR ");
const conditionValues = userPairs
@ -175,7 +175,7 @@ const buildTradeMatchesLoader = (db) =>
return [publicUserId, currentUserId, false, true];
} else {
throw new Error(
`unexpected user pair direction: ${JSON.stringify(direction)}`
`unexpected user pair direction: ${JSON.stringify(direction)}`,
);
}
})
@ -217,7 +217,7 @@ const buildTradeMatchesLoader = (db) =>
)
GROUP BY public_user_id, current_user_id;
`,
conditionValues
conditionValues,
);
const entities = rows.map(normalizeRow);
@ -227,7 +227,7 @@ const buildTradeMatchesLoader = (db) =>
(e) =>
e.publicUserId === publicUserId &&
e.currentUserId === currentUserId &&
e.direction === direction
e.direction === direction,
);
return entity ? entity.itemIds.split(",") : [];
});
@ -235,7 +235,7 @@ const buildTradeMatchesLoader = (db) =>
{
cacheKeyFn: ({ publicUserId, currentUserId, direction }) =>
`${publicUserId}-${currentUserId}-${direction}`,
}
},
);
const loadAllPetTypes = (db) => async () => {
@ -249,7 +249,7 @@ const buildItemLoader = (db) =>
const qs = ids.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM items WHERE id IN (${qs})`,
ids
ids,
);
const entities = rows.map(normalizeRow);
@ -258,7 +258,7 @@ const buildItemLoader = (db) =>
return ids.map(
(id) =>
entitiesById.get(String(id)) ||
new Error(`could not find item with ID: ${id}`)
new Error(`could not find item with ID: ${id}`),
);
});
@ -267,7 +267,7 @@ const buildItemTranslationLoader = (db) =>
const qs = itemIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM item_translations WHERE item_id IN (${qs}) AND locale = "en"`,
itemIds
itemIds,
);
const entities = rows.map(normalizeRow);
@ -276,7 +276,7 @@ const buildItemTranslationLoader = (db) =>
return itemIds.map(
(itemId) =>
entitiesByItemId.get(String(itemId)) ||
new Error(`could not find translation for item ${itemId}`)
new Error(`could not find translation for item ${itemId}`),
);
});
@ -293,7 +293,7 @@ const buildItemByNameLoader = (db, loaders) =>
WHERE name IN (${qs}) AND locale = "en"`,
nestTables: true,
},
normalizedNames
normalizedNames,
);
const entitiesByName = new Map();
@ -309,10 +309,10 @@ const buildItemByNameLoader = (db, loaders) =>
return normalizedNames.map(
(name) =>
entitiesByName.get(name) || { item: null, itemTranslation: null }
entitiesByName.get(name) || { item: null, itemTranslation: null },
);
},
{ cacheKeyFn: (name) => name.trim().toLowerCase() }
{ cacheKeyFn: (name) => name.trim().toLowerCase() },
);
const itemSearchKindConditions = {
@ -409,11 +409,8 @@ const buildItemSearchNumTotalItemsLoader = (db) =>
currentUserId,
zoneIds = [],
}) => {
const {
queryJoins,
queryConditions,
queryConditionValues,
} = buildItemSearchConditions({
const { queryJoins, queryConditions, queryConditionValues } =
buildItemSearchConditions({
query,
bodyId,
itemKind,
@ -428,12 +425,12 @@ const buildItemSearchNumTotalItemsLoader = (db) =>
${queryJoins}
WHERE ${queryConditions}
`,
queryConditionValues
queryConditionValues,
);
const { numTotalItems } = totalRows[0];
return numTotalItems;
}
},
);
const responses = await Promise.all(queryPromises);
@ -459,11 +456,8 @@ const buildItemSearchItemsLoader = (db, loaders) =>
const actualOffset = offset || 0;
const actualLimit = Math.min(limit || 30, 30);
const {
queryJoins,
queryConditions,
queryConditionValues,
} = buildItemSearchConditions({
const { queryJoins, queryConditions, queryConditionValues } =
buildItemSearchConditions({
query,
bodyId,
itemKind,
@ -480,7 +474,7 @@ const buildItemSearchItemsLoader = (db, loaders) =>
ORDER BY t.name
LIMIT ? OFFSET ?
`,
[...queryConditionValues, actualLimit, actualOffset]
[...queryConditionValues, actualLimit, actualOffset],
);
const entities = rows.map(normalizeRow);
@ -490,7 +484,7 @@ const buildItemSearchItemsLoader = (db, loaders) =>
}
return entities;
}
},
);
const responses = await Promise.all(queryPromises);
@ -504,12 +498,12 @@ const buildNewestItemsLoader = (db, loaders) =>
// loaders, even though there's only one query to run.
if (keys.length !== 1 && keys[0] !== "all-newest") {
throw new Error(
`this loader can only be loaded with the key "all-newest"`
`this loader can only be loaded with the key "all-newest"`,
);
}
const [rows] = await db.execute(
`SELECT * FROM items ORDER BY created_at DESC LIMIT 20;`
`SELECT * FROM items ORDER BY created_at DESC LIMIT 20;`,
);
const entities = rows.map(normalizeRow);
@ -616,7 +610,7 @@ async function runItemModelingQuery(db, filterToItemIds) {
-- take up a bunch of resources and crash the site?
LIMIT 200;
`,
[...itemIdsValues]
[...itemIdsValues],
);
}
@ -638,10 +632,10 @@ const buildSpeciesThatNeedModelsForItemLoader = (db) =>
// color built into the query (well, no row when no models needed!). So,
// find the right row for each color/item pair, or possibly null!
return colorIdAndItemIdPairs.map(({ colorId, itemId }) =>
entities.find((e) => e.itemId === itemId && e.colorId === colorId)
entities.find((e) => e.itemId === itemId && e.colorId === colorId),
);
},
{ cacheKeyFn: ({ colorId, itemId }) => `${colorId}-${itemId}` }
{ cacheKeyFn: ({ colorId, itemId }) => `${colorId}-${itemId}` },
);
const buildItemsThatNeedModelsLoader = (db, loaders) =>
@ -661,7 +655,7 @@ const buildItemsThatNeedModelsLoader = (db, loaders) =>
for (const { colorId, itemId, ...entity } of entities) {
loaders.speciesThatNeedModelsForItemLoader.prime(
{ colorId, itemId },
entity
entity,
);
if (!result.has(colorId)) {
@ -697,7 +691,7 @@ const buildAllSpeciesIdsForColorLoader = (db) =>
)
GROUP BY color_id;
`,
colorIds
colorIds,
);
const entities = rows.map(normalizeRow);
@ -705,7 +699,7 @@ const buildAllSpeciesIdsForColorLoader = (db) =>
return colorIds.map(
(colorId) =>
entities.find((e) => e.colorId === colorId)?.speciesIds?.split(",") ||
[]
[],
);
});
@ -731,7 +725,7 @@ const buildItemBodiesWithAppearanceDataLoader = (db) =>
ORDER BY
pet_types.species_id,
colors.standard DESC`,
itemIds
itemIds,
);
const entities = rows.map(normalizeRow);
@ -749,7 +743,7 @@ const buildItemAllOccupiedZonesLoader = (db) =>
INNER JOIN swf_assets sa ON sa.id = psa.swf_asset_id
WHERE items.id IN (${qs})
GROUP BY items.id;`,
itemIds
itemIds,
);
const entities = rows.map(normalizeRow);
@ -787,7 +781,7 @@ const buildItemCompatibleBodiesAndTheirZonesLoader = (db) =>
-- matches no pet type. Huh! Well, ignore those bodies!
HAVING speciesId IS NOT NULL OR bodyId = 0;
`,
itemIds
itemIds,
);
const entities = rows.map(normalizeRow);
@ -829,7 +823,7 @@ const buildItemTradesLoader = (db, loaders) =>
`,
nestTables: true,
},
values
values,
);
const entities = rows.map((row) => ({
@ -848,16 +842,16 @@ const buildItemTradesLoader = (db, loaders) =>
.filter(
(e) =>
e.closetHanger.itemId === itemId &&
Boolean(e.closetHanger.owned) === isOwned
Boolean(e.closetHanger.owned) === isOwned,
)
.map((e) => ({
id: e.closetHanger.id,
closetList: e.closetList.id ? e.closetList : null,
user: e.user,
}))
})),
);
},
{ cacheKeyFn: ({ itemId, isOwned }) => `${itemId}-${isOwned}` }
{ cacheKeyFn: ({ itemId, isOwned }) => `${itemId}-${isOwned}` },
);
const buildPetTypeLoader = (db, loaders) =>
@ -865,7 +859,7 @@ const buildPetTypeLoader = (db, loaders) =>
const qs = petTypeIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM pet_types WHERE id IN (${qs})`,
petTypeIds
petTypeIds,
);
const entities = rows.map(normalizeRow);
@ -873,12 +867,12 @@ const buildPetTypeLoader = (db, loaders) =>
for (const petType of entities) {
loaders.petTypeBySpeciesAndColorLoader.prime(
{ speciesId: petType.speciesId, colorId: petType.colorId },
petType
petType,
);
}
return petTypeIds.map((petTypeId) =>
entities.find((e) => e.id === petTypeId)
entities.find((e) => e.id === petTypeId),
);
});
@ -894,12 +888,12 @@ const buildPetTypeBySpeciesAndColorLoader = (db, loaders) =>
const [rows] = await db.execute(
`SELECT * FROM pet_types WHERE ${conditions.join(" OR ")}`,
values
values,
);
const entities = rows.map(normalizeRow);
const entitiesBySpeciesAndColorPair = new Map(
entities.map((e) => [`${e.speciesId},${e.colorId}`, e])
entities.map((e) => [`${e.speciesId},${e.colorId}`, e]),
);
for (const petType of entities) {
@ -907,10 +901,10 @@ const buildPetTypeBySpeciesAndColorLoader = (db, loaders) =>
}
return speciesAndColorPairs.map(({ speciesId, colorId }) =>
entitiesBySpeciesAndColorPair.get(`${speciesId},${colorId}`)
entitiesBySpeciesAndColorPair.get(`${speciesId},${colorId}`),
);
},
{ cacheKeyFn: ({ speciesId, colorId }) => `${speciesId},${colorId}` }
{ cacheKeyFn: ({ speciesId, colorId }) => `${speciesId},${colorId}` },
);
const buildPetTypesForColorLoader = (db, loaders) =>
@ -918,7 +912,7 @@ const buildPetTypesForColorLoader = (db, loaders) =>
const qs = colorIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM pet_types WHERE color_id IN (${qs})`,
colorIds
colorIds,
);
const entities = rows.map(normalizeRow);
@ -927,12 +921,27 @@ const buildPetTypesForColorLoader = (db, loaders) =>
loaders.petTypeLoader.prime(petType.id, petType);
loaders.petTypeBySpeciesAndColorLoader.prime(
{ speciesId: petType.speciesId, colorId: petType.colorId },
petType
petType,
);
}
return colorIds.map((colorId) =>
entities.filter((e) => e.colorId === colorId)
entities.filter((e) => e.colorId === colorId),
);
});
const buildAltStyleLoader = (db) =>
new DataLoader(async (altStyleIds) => {
const qs = altStyleIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM alt_styles WHERE id IN (${qs})`,
altStyleIds,
);
const entities = rows.map(normalizeRow);
return altStyleIds.map((altStyleId) =>
entities.find((e) => e.id === altStyleId),
);
});
@ -941,13 +950,13 @@ const buildSwfAssetLoader = (db) =>
const qs = swfAssetIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM swf_assets WHERE id IN (${qs})`,
swfAssetIds
swfAssetIds,
);
const entities = rows.map(normalizeRow);
return swfAssetIds.map((swfAssetId) =>
entities.find((e) => e.id === swfAssetId)
entities.find((e) => e.id === swfAssetId),
);
});
@ -960,7 +969,7 @@ const buildSwfAssetCountLoader = (db) =>
(manifest IS NOT NULL AND manifest != "") AS is_converted
FROM swf_assets
GROUP BY type, is_converted;
`
`,
);
const entities = rows.map(normalizeRow);
@ -972,7 +981,7 @@ const buildSwfAssetCountLoader = (db) =>
}
if (isConverted != null) {
matchingEntities = matchingEntities.filter(
(e) => Boolean(e.isConverted) === isConverted
(e) => Boolean(e.isConverted) === isConverted,
);
}
@ -982,7 +991,7 @@ const buildSwfAssetCountLoader = (db) =>
},
{
cacheKeyFn: ({ type, isConverted }) => `${type},${isConverted}`,
}
},
);
const buildSwfAssetByRemoteIdLoader = (db) =>
@ -996,16 +1005,16 @@ const buildSwfAssetByRemoteIdLoader = (db) =>
.flat();
const [rows] = await db.execute(
`SELECT * FROM swf_assets WHERE ${qs}`,
values
values,
);
const entities = rows.map(normalizeRow);
return typeAndRemoteIdPairs.map(({ type, remoteId }) =>
entities.find((e) => e.type === type && e.remoteId === remoteId)
entities.find((e) => e.type === type && e.remoteId === remoteId),
);
},
{ cacheKeyFn: ({ type, remoteId }) => `${type},${remoteId}` }
{ cacheKeyFn: ({ type, remoteId }) => `${type},${remoteId}` },
);
const buildItemSwfAssetLoader = (db, loaders) =>
@ -1015,7 +1024,7 @@ const buildItemSwfAssetLoader = (db, loaders) =>
const values = [];
for (const { itemId, bodyId } of itemAndBodyPairs) {
conditions.push(
"(rel.parent_id = ? AND (sa.body_id = ? OR sa.body_id = 0))"
"(rel.parent_id = ? AND (sa.body_id = ? OR sa.body_id = 0))",
);
values.push(itemId, bodyId);
}
@ -1026,7 +1035,7 @@ const buildItemSwfAssetLoader = (db, loaders) =>
rel.parent_type = "Item" AND
rel.swf_asset_id = sa.id
WHERE ${conditions.join(" OR ")}`,
values
values,
);
const entities = rows.map(normalizeRow);
@ -1038,11 +1047,11 @@ const buildItemSwfAssetLoader = (db, loaders) =>
return itemAndBodyPairs.map(({ itemId, bodyId }) =>
entities.filter(
(e) =>
e.parentId === itemId && (e.bodyId === bodyId || e.bodyId === "0")
)
e.parentId === itemId && (e.bodyId === bodyId || e.bodyId === "0"),
),
);
},
{ cacheKeyFn: ({ itemId, bodyId }) => `${itemId},${bodyId}` }
{ cacheKeyFn: ({ itemId, bodyId }) => `${itemId},${bodyId}` },
);
const buildPetSwfAssetLoader = (db, loaders) =>
@ -1054,7 +1063,7 @@ const buildPetSwfAssetLoader = (db, loaders) =>
rel.parent_type = "PetState" AND
rel.swf_asset_id = sa.id
WHERE rel.parent_id IN (${qs})`,
petStateIds
petStateIds,
);
const entities = rows.map(normalizeRow);
@ -1064,7 +1073,7 @@ const buildPetSwfAssetLoader = (db, loaders) =>
}
return petStateIds.map((petStateId) =>
entities.filter((e) => e.parentId === petStateId)
entities.filter((e) => e.parentId === petStateId),
);
});
@ -1073,7 +1082,7 @@ const buildNeopetsConnectionLoader = (db) =>
const qs = ids.map((_) => "?").join(", ");
const [rows] = await db.execute(
`SELECT * FROM neopets_connections WHERE id IN (${qs})`,
ids
ids,
);
const entities = rows.map(normalizeRow);
@ -1086,7 +1095,7 @@ const buildOutfitLoader = (db) =>
const qs = outfitIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM outfits WHERE id IN (${qs})`,
outfitIds
outfitIds,
);
const entities = rows.map(normalizeRow);
@ -1099,13 +1108,13 @@ const buildItemOutfitRelationshipsLoader = (db) =>
const qs = outfitIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM item_outfit_relationships WHERE outfit_id IN (${qs})`,
outfitIds
outfitIds,
);
const entities = rows.map(normalizeRow);
return outfitIds.map((outfitId) =>
entities.filter((e) => e.outfitId === outfitId)
entities.filter((e) => e.outfitId === outfitId),
);
});
@ -1114,13 +1123,13 @@ const buildPetStateLoader = (db) =>
const qs = petStateIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM pet_states WHERE id IN (${qs})`,
petStateIds
petStateIds,
);
const entities = rows.map(normalizeRow);
return petStateIds.map((petStateId) =>
entities.find((e) => e.id === petStateId)
entities.find((e) => e.id === petStateId),
);
});
@ -1132,7 +1141,7 @@ const buildPetStatesForPetTypeLoader = (db, loaders) =>
WHERE pet_type_id IN (${qs})
ORDER BY (mood_id IS NULL) ASC, mood_id ASC, female DESC,
unconverted DESC, glitched ASC, id DESC`,
petTypeIds
petTypeIds,
);
const entities = rows.map(normalizeRow);
@ -1142,7 +1151,7 @@ const buildPetStatesForPetTypeLoader = (db, loaders) =>
}
return petTypeIds.map((petTypeId) =>
entities.filter((e) => e.petTypeId === petTypeId)
entities.filter((e) => e.petTypeId === petTypeId),
);
});
@ -1184,7 +1193,7 @@ const buildCanonicalPetStateForBodyLoader = (db, loaders) =>
preferredColorId || "<ignore>",
fallbackColorId,
gender === "fem",
]
],
);
const petState = normalizeRow(rows[0].pet_states);
const petType = normalizeRow(rows[0].pet_types);
@ -1196,13 +1205,13 @@ const buildCanonicalPetStateForBodyLoader = (db, loaders) =>
loaders.petTypeLoader.prime(petType.id, petType);
return petState;
})
}),
);
},
{
cacheKeyFn: ({ bodyId, preferredColorId, fallbackColorId }) =>
`${bodyId}-${preferredColorId}-${fallbackColorId}`,
}
},
);
const buildPetStateByPetTypeAndAssetsLoader = (db, loaders) =>
@ -1216,7 +1225,7 @@ const buildPetStateByPetTypeAndAssetsLoader = (db, loaders) =>
.flat();
const [rows] = await db.execute(
`SELECT * FROM pet_states WHERE ${qs}`,
values
values,
);
const entities = rows.map(normalizeRow);
@ -1227,13 +1236,13 @@ const buildPetStateByPetTypeAndAssetsLoader = (db, loaders) =>
return petTypeIdAndAssetIdsPairs.map(({ petTypeId, swfAssetIds }) =>
entities.find(
(e) => e.petTypeId === petTypeId && e.swfAssetIds === swfAssetIds
)
(e) => e.petTypeId === petTypeId && e.swfAssetIds === swfAssetIds,
),
);
},
{
cacheKeyFn: ({ petTypeId, swfAssetIds }) => `${petTypeId}-${swfAssetIds}`,
}
},
);
const buildUserLoader = (db) =>
@ -1241,7 +1250,7 @@ const buildUserLoader = (db) =>
const qs = ids.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM users WHERE id IN (${qs})`,
ids
ids,
);
const entities = rows.map(normalizeRow);
@ -1250,7 +1259,7 @@ const buildUserLoader = (db) =>
return ids.map(
(id) =>
entitiesById.get(String(id)) ||
new Error(`could not find user with ID: ${id}`)
new Error(`could not find user with ID: ${id}`),
);
});
@ -1259,13 +1268,13 @@ const buildUserByNameLoader = (db) =>
const qs = names.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM users WHERE name IN (${qs})`,
names
names,
);
const entities = rows.map(normalizeRow);
return names.map((name) =>
entities.find((e) => e.name.toLowerCase() === name.toLowerCase())
entities.find((e) => e.name.toLowerCase() === name.toLowerCase()),
);
});
@ -1281,7 +1290,7 @@ const buildUserByEmailLoader = (db) =>
`,
nestTables: true,
},
emails
emails,
);
const entities = rows.map((row) => ({
@ -1302,12 +1311,12 @@ const buildUserClosetHangersLoader = (db) =>
item_translations.item_id = items.id AND locale = "en"
WHERE user_id IN (${qs})
ORDER BY item_name`,
userIds
userIds,
);
const entities = rows.map(normalizeRow);
return userIds.map((userId) =>
entities.filter((e) => e.userId === String(userId))
entities.filter((e) => e.userId === String(userId)),
);
});
@ -1321,12 +1330,12 @@ const buildUserItemClosetHangersLoader = (db) =>
.flat();
const [rows] = await db.execute(
`SELECT * FROM closet_hangers WHERE ${conditions};`,
params
params,
);
const entities = rows.map(normalizeRow);
return userIdAndItemIdPairs.map(({ userId, itemId }) =>
entities.filter((e) => e.userId === userId && e.itemId === itemId)
entities.filter((e) => e.userId === userId && e.itemId === itemId),
);
});
@ -1337,7 +1346,7 @@ const buildUserClosetListsLoader = (db, loaders) =>
`SELECT * FROM closet_lists
WHERE user_id IN (${qs})
ORDER BY name`,
userIds
userIds,
);
const entities = rows.map(normalizeRow);
@ -1346,7 +1355,7 @@ const buildUserClosetListsLoader = (db, loaders) =>
}
return userIds.map((userId) =>
entities.filter((e) => e.userId === String(userId))
entities.filter((e) => e.userId === String(userId)),
);
});
@ -1363,7 +1372,7 @@ const buildUserOutfitsLoader = (db, loaders) =>
WHERE user_id = ?
ORDER BY name
LIMIT ? OFFSET ?`,
[userId, actualLimit, actualOffset]
[userId, actualLimit, actualOffset],
);
const entities = rows.map(normalizeRow);
@ -1382,7 +1391,7 @@ const buildUserNumTotalOutfitsLoader = (db) =>
`SELECT user_id, COUNT(*) as num_total_outfits FROM outfits
WHERE user_id IN (${qs})
GROUP BY user_id`,
userIds
userIds,
);
const entities = rows.map(normalizeRow);
@ -1435,7 +1444,7 @@ const buildUserLastTradeActivityLoader = (db) =>
)
GROUP BY closet_hangers.user_id
`,
userIds
userIds,
);
const entities = rows.map(normalizeRow);
@ -1451,7 +1460,7 @@ const buildZoneLoader = (db) => {
const qs = ids.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM zones WHERE id IN (${qs})`,
ids
ids,
);
const entities = rows.map(normalizeRow);
@ -1460,7 +1469,7 @@ const buildZoneLoader = (db) => {
return ids.map(
(id) =>
entitiesById.get(String(id)) ||
new Error(`could not find zone with ID: ${id}`)
new Error(`could not find zone with ID: ${id}`),
);
});
@ -1483,7 +1492,7 @@ const buildZoneTranslationLoader = (db) =>
const qs = zoneIds.map((_) => "?").join(",");
const [rows] = await db.execute(
`SELECT * FROM zone_translations WHERE zone_id IN (${qs}) AND locale = "en"`,
zoneIds
zoneIds,
);
const entities = rows.map(normalizeRow);
@ -1492,7 +1501,7 @@ const buildZoneTranslationLoader = (db) =>
return zoneIds.map(
(zoneId) =>
entitiesByZoneId.get(String(zoneId)) ||
new Error(`could not find translation for zone ${zoneId}`)
new Error(`could not find translation for zone ${zoneId}`),
);
});
@ -1502,41 +1511,37 @@ function buildLoaders(db) {
loaders.closetListLoader = buildClosetListLoader(db);
loaders.closetHangersForListLoader = buildClosetHangersForListLoader(db);
loaders.closetHangersForDefaultListLoader = buildClosetHangersForDefaultListLoader(
db
);
loaders.closetHangersForDefaultListLoader =
buildClosetHangersForDefaultListLoader(db);
loaders.colorLoader = buildColorLoader(db);
loaders.colorTranslationLoader = buildColorTranslationLoader(db);
loaders.itemLoader = buildItemLoader(db);
loaders.itemTranslationLoader = buildItemTranslationLoader(db);
loaders.itemByNameLoader = buildItemByNameLoader(db, loaders);
loaders.itemSearchNumTotalItemsLoader = buildItemSearchNumTotalItemsLoader(
db
);
loaders.itemSearchNumTotalItemsLoader =
buildItemSearchNumTotalItemsLoader(db);
loaders.itemSearchItemsLoader = buildItemSearchItemsLoader(db, loaders);
loaders.newestItemsLoader = buildNewestItemsLoader(db, loaders);
loaders.speciesThatNeedModelsForItemLoader = buildSpeciesThatNeedModelsForItemLoader(
db
);
loaders.speciesThatNeedModelsForItemLoader =
buildSpeciesThatNeedModelsForItemLoader(db);
loaders.itemsThatNeedModelsLoader = buildItemsThatNeedModelsLoader(
db,
loaders
loaders,
);
loaders.allSpeciesIdsForColorLoader = buildAllSpeciesIdsForColorLoader(db);
loaders.itemBodiesWithAppearanceDataLoader = buildItemBodiesWithAppearanceDataLoader(
db
);
loaders.itemBodiesWithAppearanceDataLoader =
buildItemBodiesWithAppearanceDataLoader(db);
loaders.itemAllOccupiedZonesLoader = buildItemAllOccupiedZonesLoader(db);
loaders.itemCompatibleBodiesAndTheirZonesLoader = buildItemCompatibleBodiesAndTheirZonesLoader(
db
);
loaders.itemCompatibleBodiesAndTheirZonesLoader =
buildItemCompatibleBodiesAndTheirZonesLoader(db);
loaders.itemTradesLoader = buildItemTradesLoader(db, loaders);
loaders.petTypeLoader = buildPetTypeLoader(db, loaders);
loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader(
db,
loaders
loaders,
);
loaders.petTypesForColorLoader = buildPetTypesForColorLoader(db, loaders);
loaders.altStyleLoader = buildAltStyleLoader(db);
loaders.swfAssetLoader = buildSwfAssetLoader(db);
loaders.swfAssetCountLoader = buildSwfAssetCountLoader(db);
loaders.swfAssetByRemoteIdLoader = buildSwfAssetByRemoteIdLoader(db);
@ -1544,22 +1549,19 @@ function buildLoaders(db) {
loaders.petSwfAssetLoader = buildPetSwfAssetLoader(db, loaders);
loaders.neopetsConnectionLoader = buildNeopetsConnectionLoader(db);
loaders.outfitLoader = buildOutfitLoader(db);
loaders.itemOutfitRelationshipsLoader = buildItemOutfitRelationshipsLoader(
db
);
loaders.itemOutfitRelationshipsLoader =
buildItemOutfitRelationshipsLoader(db);
loaders.petStateLoader = buildPetStateLoader(db);
loaders.petStatesForPetTypeLoader = buildPetStatesForPetTypeLoader(
db,
loaders
loaders,
);
loaders.canonicalPetStateForBodyLoader = buildCanonicalPetStateForBodyLoader(
db,
loaders
);
loaders.petStateByPetTypeAndAssetsLoader = buildPetStateByPetTypeAndAssetsLoader(
db,
loaders
loaders,
);
loaders.petStateByPetTypeAndAssetsLoader =
buildPetStateByPetTypeAndAssetsLoader(db, loaders);
loaders.speciesLoader = buildSpeciesLoader(db);
loaders.speciesTranslationLoader = buildSpeciesTranslationLoader(db);
loaders.tradeMatchesLoader = buildTradeMatchesLoader(db);

View file

@ -70,7 +70,11 @@ const typeDefs = gql`
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! @cacheControl(maxAge: 1, staleWhileRevalidate: ${oneDay})
appearanceOn(
speciesId: ID!,
colorId: ID!,
altStyleId: ID,
): ItemAppearance! @cacheControl(maxAge: 1, staleWhileRevalidate: ${oneDay})
"""
This is set manually by Support users, when the pet is only for e.g.
@ -176,6 +180,7 @@ const typeDefs = gql`
input FitsPetSearchFilter {
speciesId: ID!
colorId: ID!
altStyleId: ID
}
enum ItemKindSearchFilter {
@ -527,9 +532,18 @@ const resolvers = {
appearanceOn: async (
{ id },
{ speciesId, colorId },
{ petTypeBySpeciesAndColorLoader },
{ speciesId, colorId, altStyleId },
{ altStyleLoader, petTypeBySpeciesAndColorLoader },
) => {
// Load based on the alt style's body ID, if present.
if (altStyleId) {
const altStyle = await altStyleLoader.load(altStyleId);
if (altStyle != null) {
return { item: { id }, bodyId: altStyle.bodyId };
}
}
// If not, load based on the species/color combo's body ID.
const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId,
colorId,
@ -763,6 +777,7 @@ const resolvers = {
itemSearchNumTotalItemsLoader,
itemSearchItemsLoader,
petTypeBySpeciesAndColorLoader,
altStyleLoader,
currentUserId,
},
{ cacheControl },
@ -773,6 +788,16 @@ const resolvers = {
let bodyId = null;
if (fitsPet) {
// Load based on the alt style's body ID, if present.
if (fitsPet.altStyleId != null) {
const altStyle = altStyleLoader.load(fitsPet.altStyleId);
if (altStyle) {
bodyId = altStyle.bodyId;
}
}
// If not, load based on the species/color combo's body ID.
if (bodyId == null) {
const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId: fitsPet.speciesId,
colorId: fitsPet.colorId,
@ -785,6 +810,7 @@ const resolvers = {
}
bodyId = petType.bodyId;
}
}
const [items, numTotalItems] = await Promise.all([
itemSearchItemsLoader.load({
query: query.trim(),
@ -811,10 +837,20 @@ const resolvers = {
itemSearchV2: async (
_,
{ query, fitsPet, itemKind, currentUserOwnsOrWants, zoneIds = [] },
{ petTypeBySpeciesAndColorLoader },
{ petTypeBySpeciesAndColorLoader, altStyleLoader },
) => {
let bodyId = null;
if (fitsPet) {
// Load based on the alt style's body ID, if present.
if (fitsPet.altStyleId != null) {
const altStyle = await altStyleLoader.load(fitsPet.altStyleId);
if (altStyle != null) {
bodyId = altStyle.bodyId;
}
}
// If not, load based on the species/color combo's body ID.
if (bodyId == null) {
const petType = await petTypeBySpeciesAndColorLoader.load({
speciesId: fitsPet.speciesId,
colorId: fitsPet.colorId,
@ -827,6 +863,7 @@ const resolvers = {
}
bodyId = petType.bodyId;
}
}
// These are the fields that define the search! We provide them to the
// ItemSearchResultV2 resolvers, and also stringify them into an `id` for