set bodyId=0 when item's body id changes

that is, if we see an item modeled on a second body, then treat it as body 0
This commit is contained in:
Emi Matchu 2020-09-25 05:04:12 -07:00
parent 96a126ebba
commit cc5a8a6fab
4 changed files with 502 additions and 16 deletions

View file

@ -308,4 +308,40 @@ describe("Pet", () => {
});
expect(getDbCalls()).toMatchSnapshot();
});
it("sets bodyId=0 after seeing it on two body types", async () => {
useTestDb();
// First, write the Moon and Stars Background SWF to the database, but with
// the Standard Acara body ID set.
const db = await connectToDb();
await db.query(
`INSERT INTO swf_assets (type, remote_id, url, zone_id, zones_restrict,
created_at, body_id)
VALUES ("object", 6829, "http://images.neopets.com/cp/items/swf/000/000/006/6829_1707e50385.swf",
3, "", CURRENT_TIMESTAMP(), 93);`
);
clearDbCalls();
// Then, model a Zafara wearing it.
await query({
query: gql`
query {
petOnNeopetsDotCom(petName: "roopal27") {
id
}
}
`,
});
expect(getDbCalls()).toMatchSnapshot("db");
// The body ID should be 0 now.
const [rows, _] = await db.query(
`SELECT body_id FROM swf_assets
WHERE type = "object" AND remote_id = 6829;`
);
expect(rows[0].body_id).toEqual(0);
});
});

View file

@ -1145,3 +1145,406 @@ Array [
],
]
`;
exports[`Pet sets bodyId=0 after seeing it on two body types: db 1`] = `
Array [
Array [
"SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)",
Array [
"54",
"75",
],
],
Array [
"SELECT * FROM items WHERE id IN (?,?,?,?,?,?,?,?)",
Array [
"37229",
"37375",
"38911",
"38912",
"38913",
"43014",
"43397",
"48313",
],
],
Array [
"SELECT * FROM item_translations WHERE item_id IN (?,?,?,?,?,?,?,?) AND locale = \\"en\\"",
Array [
"37229",
"37375",
"38911",
"38912",
"38913",
"43014",
"43397",
"48313",
],
],
Array [
"SELECT * FROM swf_assets WHERE (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?)",
Array [
"object",
"6829",
"object",
"14855",
"object",
"14856",
"object",
"14857",
"object",
"36414",
"object",
"39646",
"object",
"51959",
"object",
"56478",
"biology",
"7942",
"biology",
"7941",
"biology",
"24008",
"biology",
"21060",
"biology",
"21057",
"biology",
"7946",
],
],
Array [
"INSERT INTO pet_types (body_id, color_id, created_at, species_id) VALUES (?, ?, ?, ?);",
Array [
"180",
"75",
2020-01-01T00:00:00.000Z,
"54",
],
],
Array [
"INSERT INTO items (category, created_at, id, price, rarity_index, thumbnail_url, type, updated_at, weight_lbs, zones_restrict) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
Array [
"Gift",
2020-01-01T00:00:00.000Z,
"37229",
0,
101,
"http://images.neopets.com/items/gif_magicball_table.gif",
"Gift",
2020-01-01T00:00:00.000Z,
1,
"0000000000000000000000000000000000000000000000",
"Special",
2020-01-01T00:00:00.000Z,
"37375",
209,
75,
"http://images.neopets.com/items/bg_moonstars.gif",
"Mystical Surroundings",
2020-01-01T00:00:00.000Z,
1,
"0000000000000000000000000000000000000000000000000000",
"Clothes",
2020-01-01T00:00:00.000Z,
"38911",
980,
92,
"http://images.neopets.com/items/clo_zafara_agent_hood.gif",
"Clothes",
2020-01-01T00:00:00.000Z,
1,
"0000000000000000000000000000000000001100000000000000",
"Clothes",
2020-01-01T00:00:00.000Z,
"38912",
1476,
90,
"http://images.neopets.com/items/clo_zafara_agent_robe.gif",
"Clothes",
2020-01-01T00:00:00.000Z,
1,
"0000000000000000000101000000000000000000000000000000",
"Clothes",
2020-01-01T00:00:00.000Z,
"38913",
1177,
88,
"http://images.neopets.com/items/clo_zafara_agent_gloves.gif",
"Clothes",
2020-01-01T00:00:00.000Z,
1,
"0000000000000000000000000000000000000000000000000000",
"Toys",
2020-01-01T00:00:00.000Z,
"43014",
1033,
80,
"http://images.neopets.com/items/toy_stringlight_illleaf.gif",
"Toy",
2020-01-01T00:00:00.000Z,
1,
"0000000000000000000000000000000000000000000000",
"Clothes",
2020-01-01T00:00:00.000Z,
"43397",
0,
500,
"http://images.neopets.com/items/mall_staff_jewelled.gif",
"Clothes",
2020-01-01T00:00:00.000Z,
1,
"0000000000000000000000000000000000000000000000",
"Clothes",
2020-01-01T00:00:00.000Z,
"48313",
0,
101,
"http://images.neopets.com/items/clo_altcuplogo_brooch.gif",
"Clothes",
2020-01-01T00:00:00.000Z,
1,
"0000000000000000000000000000000000000000000000000000",
],
],
Array [
"INSERT INTO item_translations (created_at, description, item_id, locale, name, rarity, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?);",
Array [
2020-01-01T00:00:00.000Z,
"What does this ball actually do?",
"37229",
"en",
"Magic Ball Table",
"Special",
2020-01-01T00:00:00.000Z,
2020-01-01T00:00:00.000Z,
"Dont forget to wish upon a star.",
"37375",
"en",
"Moon and Stars Background",
"Uncommon",
2020-01-01T00:00:00.000Z,
2020-01-01T00:00:00.000Z,
"Hide your face and hair so no one can recognise you.",
"38911",
"en",
"Zafara Agent Hood",
"Very Rare",
2020-01-01T00:00:00.000Z,
2020-01-01T00:00:00.000Z,
"This robe is great for being stealthy.",
"38912",
"en",
"Zafara Agent Robe",
"Very Rare",
2020-01-01T00:00:00.000Z,
2020-01-01T00:00:00.000Z,
"Dont leave any trace that you were there with these gloves.",
"38913",
"en",
"Zafara Agent Gloves",
"Rare",
2020-01-01T00:00:00.000Z,
2020-01-01T00:00:00.000Z,
"These leaves almost look magical with their gentle glow.",
"43014",
"en",
"Green Leaf String Lights",
"Uncommon",
2020-01-01T00:00:00.000Z,
2020-01-01T00:00:00.000Z,
"This jewelled staff shines with a magical light.",
"43397",
"en",
"Jewelled Staff",
"Artifact",
2020-01-01T00:00:00.000Z,
2020-01-01T00:00:00.000Z,
"Even the announcers of the Altador Cup celebrate. This was given out by the Advent Calendar in Y11.",
"48313",
"en",
"Altador Cup Brooch",
"Special",
2020-01-01T00:00:00.000Z,
],
],
Array [
"INSERT INTO swf_assets (body_id, created_at, remote_id, type, url, zone_id, zones_restrict) VALUES (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?);",
Array [
"180",
2020-01-01T00:00:00.000Z,
"14855",
"object",
"http://images.neopets.com/cp/items/swf/000/000/014/14855_215f367070.swf",
"25",
"",
"180",
2020-01-01T00:00:00.000Z,
"14856",
"object",
"http://images.neopets.com/cp/items/swf/000/000/014/14856_46c1b32797.swf",
"26",
"",
"180",
2020-01-01T00:00:00.000Z,
"14857",
"object",
"http://images.neopets.com/cp/items/swf/000/000/014/14857_d43380ef66.swf",
"40",
"",
"180",
2020-01-01T00:00:00.000Z,
"36414",
"object",
"http://images.neopets.com/cp/items/swf/000/000/036/36414_1e2aaab4ad.swf",
"48",
"",
"180",
2020-01-01T00:00:00.000Z,
"39646",
"object",
"http://images.neopets.com/cp/items/swf/000/000/039/39646_e129e22ada.swf",
"42",
"",
"180",
2020-01-01T00:00:00.000Z,
"51959",
"object",
"http://images.neopets.com/cp/items/swf/000/000/051/51959_4439727c48.swf",
"45",
"",
"180",
2020-01-01T00:00:00.000Z,
"56478",
"object",
"http://images.neopets.com/cp/items/swf/000/000/056/56478_eabc28e7c7.swf",
"27",
"",
"0",
2020-01-01T00:00:00.000Z,
"7942",
"biology",
"http://images.neopets.com/cp/bio/swf/000/000/007/7942_2eab06fd7b.swf",
"5",
"0000000000000000000000000000000000000000000000000000",
"0",
2020-01-01T00:00:00.000Z,
"7941",
"biology",
"http://images.neopets.com/cp/bio/swf/000/000/007/7941_2c4cc4b846.swf",
"15",
"0000000000000000000000000000000000000000000000000000",
"0",
2020-01-01T00:00:00.000Z,
"24008",
"biology",
"http://images.neopets.com/cp/bio/swf/000/000/024/24008_a05fe9876a.swf",
"30",
"0000000000000000000000000000000000000000000000000000",
"0",
2020-01-01T00:00:00.000Z,
"21060",
"biology",
"http://images.neopets.com/cp/bio/swf/000/000/021/21060_d77ba93b7b.swf",
"33",
"0000000000000000000000000000000000000000000000000000",
"0",
2020-01-01T00:00:00.000Z,
"21057",
"biology",
"http://images.neopets.com/cp/bio/swf/000/000/021/21057_4550efbb2f.swf",
"34",
"0000000000000000000000000000000000000000000000000000",
"0",
2020-01-01T00:00:00.000Z,
"7946",
"biology",
"http://images.neopets.com/cp/bio/swf/000/000/007/7946_0348dad587.swf",
"37",
"0000000000000000000000000000000000000000000000000000",
],
],
Array [
"UPDATE swf_assets SET body_id = ? WHERE type = ? AND remote_id = ?;",
Array [
"0",
"object",
"6829",
],
],
Array [
"SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)",
Array [
"54",
"75",
],
],
Array [
"SELECT * FROM pet_states WHERE (pet_type_id = ? AND swf_asset_ids = ?)",
Array [
"1",
"7941,7942,7946,21057,21060,24008",
],
],
Array [
"INSERT INTO pet_states (female, labeled, mood_id, pet_type_id, swf_asset_ids, unconverted) VALUES (?, ?, ?, ?, ?, ?);",
Array [
0,
1,
"2",
"1",
"7941,7942,7946,21057,21060,24008",
0,
],
],
Array [
"SELECT * FROM pet_states WHERE (pet_type_id = ? AND swf_asset_ids = ?)",
Array [
"1",
"7941,7942,7946,21057,21060,24008",
],
],
Array [
"SELECT * FROM swf_assets WHERE (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?) OR (type = ? AND remote_id = ?)",
Array [
"biology",
"7942",
"biology",
"7941",
"biology",
"24008",
"biology",
"21060",
"biology",
"21057",
"biology",
"7946",
],
],
Array [
"INSERT INTO parents_swf_assets (parent_type, parent_id, swf_asset_id)
VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?), (?, ?, ?), (?, ?, ?), (?, ?, ?);",
Array [
"PetState",
"1",
"9",
"PetState",
"1",
"10",
"PetState",
"1",
"11",
"PetState",
"1",
"12",
"PetState",
"1",
"13",
"PetState",
"1",
"14",
],
],
]
`;

View file

@ -71,7 +71,7 @@ const typeDefs = gql`
const resolvers = {
AppearanceLayer: {
bodyId: async ({ id }, _, { swfAssetLoader }) => {
remoteId: async ({ id }, _, { swfAssetLoader }) => {
const layer = await swfAssetLoader.load(id);
return layer.remoteId;
},
@ -79,7 +79,7 @@ const resolvers = {
const layer = await swfAssetLoader.load(id);
return layer.bodyId;
},
zone: async ({ id }, _, { swfAssetLoader, zoneLoader }) => {
zone: async ({ id }, _, { swfAssetLoader }) => {
const layer = await swfAssetLoader.load(id);
return { id: layer.zoneId };
},

View file

@ -193,10 +193,33 @@ async function saveModelingData(
url: objectAsset.asset_url,
zoneId: String(objectAsset.zone_id),
zonesRestrict: "",
// TODO: This doesn't actually work... sometimes it needs to be 0, yeah?
// So we actually have to do asset writing after we load the current
// row and compare... maybe a cutesy fn syntax here?
bodyId: String(customPet.body_id),
bodyId: (currentBodyId) => {
const incomingBodyId = String(customPet.body_id);
if (currentBodyId == null) {
// If this is a new asset, use the incoming body ID. This might not be
// totally true, the real ID might be 0, but we're conservative to
// start and will update it to 0 if we see a contradiction later!
//
// NOTE: There's an explicitly_body_specific column on Item. We don't
// need to consider it here, because it's specifically to
// override the heuristics in the old app that sometimes set
// bodyId=0 for incoming items depending on their zone. We don't
// do that here!
return incomingBodyId;
} else if (currentBodyId === "0") {
// If this is already an all-bodies asset, keep it that way.
return "0";
} else if (currentBodyId !== incomingBodyId) {
// If this isn't an all-bodies asset yet, but we've now seen it on two
// different items, then make it an all-bodies asset!
return "0";
} else {
// Okay, the row already exists, and its body ID matches this one.
// No change!
return currentBodyId;
}
},
}));
const biologyAssets = Object.values(customPet.biology_by_zone);
@ -369,7 +392,21 @@ async function syncToDb(
// If there is no corresponding row in the database, prepare an insert.
// TODO: Should probably converge on whether not-found is null or an error
if (currentRow == null || currentRow instanceof Error) {
const insert = { ...incomingRow };
const insert = {};
for (const key in incomingRow) {
let incomingValue = incomingRow[key];
// If you pass a function as a value, we treat it as a merge function:
// we'll pass it the current value, and you'll use it to determine and
// return the incoming value. In this case, the row doesn't exist yet,
// so the current value is `null`.
if (typeof incomingValue === "function") {
incomingValue = incomingValue(null);
}
insert[key] = incomingValue;
}
if (includeCreatedAt) {
insert.createdAt = new Date();
}
@ -387,14 +424,24 @@ async function syncToDb(
// If there's a row in the database, and some of the values don't match,
// prepare an update with the updated fields only.
const updatedKeys = Object.keys(incomingRow).filter(
(k) => incomingRow[k] !== currentRow[k]
);
if (updatedKeys.length > 0) {
const update = {};
for (const key of updatedKeys) {
update[key] = incomingRow[key];
for (const key in incomingRow) {
const currentValue = currentRow[key];
let incomingValue = incomingRow[key];
// If you pass a function as a value, we treat it as a merge function:
// we'll pass it the current value, and you'll use it to determine and
// return the incoming value.
if (typeof incomingValue === "function") {
incomingValue = incomingValue(currentValue);
}
if (currentValue !== incomingValue) {
update[key] = incomingValue;
}
}
if (Object.keys(update).length > 0) {
if (includeUpdatedAt) {
update.updatedAt = new Date();
}
@ -417,10 +464,10 @@ async function syncToDb(
const columnsStr = columnNames.join(", ");
const qs = columnNames.map((_) => "?").join(", ");
const rowQs = inserts.map((_) => "(" + qs + ")").join(", ");
const rowFields = inserts.map((row) => rowKeys.map((key) => row[key]));
const rowValues = inserts.map((row) => rowKeys.map((key) => row[key]));
await db.execute(
`INSERT INTO ${tableName} (${columnsStr}) VALUES ${rowQs};`,
rowFields.flat()
rowValues.flat()
);
if (afterInsert) {
await afterInsert();