modeling will save new item data (but not assets)
just a first step!
This commit is contained in:
parent
07691a4e6b
commit
dfeeb9fe0d
6 changed files with 467 additions and 11 deletions
|
@ -133,4 +133,4 @@ UNLOCK TABLES;
|
|||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2020-09-18 5:47:49
|
||||
-- Dump completed on 2020-09-18 6:27:12
|
||||
|
|
|
@ -32,7 +32,7 @@ CREATE TABLE `items` (
|
|||
`price` mediumint(9) NOT NULL,
|
||||
`weight_lbs` smallint(6) DEFAULT NULL,
|
||||
`species_support_ids` mediumtext COLLATE utf8_unicode_ci,
|
||||
`sold_in_mall` tinyint(1) NOT NULL,
|
||||
`sold_in_mall` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`last_spidered` datetime DEFAULT NULL,
|
||||
`created_at` datetime DEFAULT NULL,
|
||||
`updated_at` datetime DEFAULT NULL,
|
||||
|
@ -77,4 +77,4 @@ CREATE TABLE `item_translations` (
|
|||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2020-09-18 5:47:52
|
||||
-- Dump completed on 2020-09-18 6:27:15
|
||||
|
|
|
@ -51,7 +51,7 @@ describe("Pet", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it.skip("models new item data", async () => {
|
||||
it("models new item data", async () => {
|
||||
useTestDb();
|
||||
|
||||
const res = await query({
|
||||
|
@ -73,7 +73,7 @@ describe("Pet", () => {
|
|||
|
||||
expect(res).toHaveNoErrors();
|
||||
expect(res.data).toMatchSnapshot();
|
||||
expect(getDbCalls()).toMatchInlineSnapshot(`Array []`);
|
||||
expect(getDbCalls()).toMatchSnapshot();
|
||||
|
||||
clearDbCalls();
|
||||
|
||||
|
@ -98,6 +98,7 @@ describe("Pet", () => {
|
|||
thumbnailUrl
|
||||
rarityIndex
|
||||
isNc
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
`,
|
||||
|
@ -105,6 +106,35 @@ describe("Pet", () => {
|
|||
|
||||
expect(res2).toHaveNoErrors();
|
||||
expect(res2.data).toMatchSnapshot();
|
||||
expect(getDbCalls()).toMatchInlineSnapshot();
|
||||
expect(getDbCalls()).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"SELECT * FROM item_translations WHERE item_id IN (?,?,?,?,?,?,?,?) AND locale = \\"en\\"",
|
||||
Array [
|
||||
"37229",
|
||||
"37375",
|
||||
"38911",
|
||||
"38912",
|
||||
"38913",
|
||||
"43014",
|
||||
"43397",
|
||||
"48313",
|
||||
],
|
||||
],
|
||||
Array [
|
||||
"SELECT * FROM items WHERE id IN (?,?,?,?,?,?,?,?)",
|
||||
Array [
|
||||
"37229",
|
||||
"37375",
|
||||
"38911",
|
||||
"38912",
|
||||
"38913",
|
||||
"43014",
|
||||
"43397",
|
||||
"48313",
|
||||
],
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -154,3 +154,267 @@ Object {
|
|||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Pet models new item data 2`] = `
|
||||
Array [
|
||||
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 [
|
||||
"INSERT INTO items
|
||||
(
|
||||
id, zones_restrict, thumbnail_url, category, type, rarity_index,
|
||||
price, weight_lbs, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
",
|
||||
Array [
|
||||
"37229",
|
||||
"0000000000000000000000000000000000000000000000",
|
||||
"http://images.neopets.com/items/gif_magicball_table.gif",
|
||||
"Gift",
|
||||
"Gift",
|
||||
101,
|
||||
0,
|
||||
1,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"37375",
|
||||
"0000000000000000000000000000000000000000000000000000",
|
||||
"http://images.neopets.com/items/bg_moonstars.gif",
|
||||
"Special",
|
||||
"Mystical Surroundings",
|
||||
75,
|
||||
209,
|
||||
1,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"38911",
|
||||
"0000000000000000000000000000000000001100000000000000",
|
||||
"http://images.neopets.com/items/clo_zafara_agent_hood.gif",
|
||||
"Clothes",
|
||||
"Clothes",
|
||||
92,
|
||||
980,
|
||||
1,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"38912",
|
||||
"0000000000000000000101000000000000000000000000000000",
|
||||
"http://images.neopets.com/items/clo_zafara_agent_robe.gif",
|
||||
"Clothes",
|
||||
"Clothes",
|
||||
90,
|
||||
1476,
|
||||
1,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"38913",
|
||||
"0000000000000000000000000000000000000000000000000000",
|
||||
"http://images.neopets.com/items/clo_zafara_agent_gloves.gif",
|
||||
"Clothes",
|
||||
"Clothes",
|
||||
88,
|
||||
1177,
|
||||
1,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"43014",
|
||||
"0000000000000000000000000000000000000000000000",
|
||||
"http://images.neopets.com/items/toy_stringlight_illleaf.gif",
|
||||
"Toys",
|
||||
"Toy",
|
||||
80,
|
||||
1033,
|
||||
1,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"43397",
|
||||
"0000000000000000000000000000000000000000000000",
|
||||
"http://images.neopets.com/items/mall_staff_jewelled.gif",
|
||||
"Clothes",
|
||||
"Clothes",
|
||||
500,
|
||||
0,
|
||||
1,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"48313",
|
||||
"0000000000000000000000000000000000000000000000000000",
|
||||
"http://images.neopets.com/items/clo_altcuplogo_brooch.gif",
|
||||
"Clothes",
|
||||
"Clothes",
|
||||
101,
|
||||
0,
|
||||
1,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
],
|
||||
],
|
||||
Array [
|
||||
"INSERT INTO item_translations
|
||||
(item_id, locale, name, description, rarity, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?);",
|
||||
Array [
|
||||
"37229",
|
||||
"en",
|
||||
"Magic Ball Table",
|
||||
"What does this ball actually do?",
|
||||
"Special",
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"37375",
|
||||
"en",
|
||||
"Moon and Stars Background",
|
||||
"Dont forget to wish upon a star.",
|
||||
"Uncommon",
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"38911",
|
||||
"en",
|
||||
"Zafara Agent Hood",
|
||||
"Hide your face and hair so no one can recognise you.",
|
||||
"Very Rare",
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"38912",
|
||||
"en",
|
||||
"Zafara Agent Robe",
|
||||
"This robe is great for being stealthy.",
|
||||
"Very Rare",
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"38913",
|
||||
"en",
|
||||
"Zafara Agent Gloves",
|
||||
"Dont leave any trace that you were there with these gloves.",
|
||||
"Rare",
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"43014",
|
||||
"en",
|
||||
"Green Leaf String Lights",
|
||||
"These leaves almost look magical with their gentle glow.",
|
||||
"Uncommon",
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"43397",
|
||||
"en",
|
||||
"Jewelled Staff",
|
||||
"This jewelled staff shines with a magical light.",
|
||||
"Artifact",
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
"48313",
|
||||
"en",
|
||||
"Altador Cup Brooch",
|
||||
"Even the announcers of the Altador Cup celebrate. This was given out by the Advent Calendar in Y11.",
|
||||
"Special",
|
||||
2020-01-01T00:00:00.000Z,
|
||||
2020-01-01T00:00:00.000Z,
|
||||
],
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Pet models new item data 3`] = `
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"description": "What does this ball actually do?",
|
||||
"id": "37229",
|
||||
"isNc": false,
|
||||
"name": "Magic Ball Table",
|
||||
"rarityIndex": 101,
|
||||
"thumbnailUrl": "http://images.neopets.com/items/gif_magicball_table.gif",
|
||||
},
|
||||
Object {
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"description": "Dont forget to wish upon a star.",
|
||||
"id": "37375",
|
||||
"isNc": false,
|
||||
"name": "Moon and Stars Background",
|
||||
"rarityIndex": 75,
|
||||
"thumbnailUrl": "http://images.neopets.com/items/bg_moonstars.gif",
|
||||
},
|
||||
Object {
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"description": "Hide your face and hair so no one can recognise you.",
|
||||
"id": "38911",
|
||||
"isNc": false,
|
||||
"name": "Zafara Agent Hood",
|
||||
"rarityIndex": 92,
|
||||
"thumbnailUrl": "http://images.neopets.com/items/clo_zafara_agent_hood.gif",
|
||||
},
|
||||
Object {
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"description": "This robe is great for being stealthy.",
|
||||
"id": "38912",
|
||||
"isNc": false,
|
||||
"name": "Zafara Agent Robe",
|
||||
"rarityIndex": 90,
|
||||
"thumbnailUrl": "http://images.neopets.com/items/clo_zafara_agent_robe.gif",
|
||||
},
|
||||
Object {
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"description": "Dont leave any trace that you were there with these gloves.",
|
||||
"id": "38913",
|
||||
"isNc": false,
|
||||
"name": "Zafara Agent Gloves",
|
||||
"rarityIndex": 88,
|
||||
"thumbnailUrl": "http://images.neopets.com/items/clo_zafara_agent_gloves.gif",
|
||||
},
|
||||
Object {
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"description": "These leaves almost look magical with their gentle glow.",
|
||||
"id": "43014",
|
||||
"isNc": false,
|
||||
"name": "Green Leaf String Lights",
|
||||
"rarityIndex": 80,
|
||||
"thumbnailUrl": "http://images.neopets.com/items/toy_stringlight_illleaf.gif",
|
||||
},
|
||||
Object {
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"description": "This jewelled staff shines with a magical light.",
|
||||
"id": "43397",
|
||||
"isNc": true,
|
||||
"name": "Jewelled Staff",
|
||||
"rarityIndex": 500,
|
||||
"thumbnailUrl": "http://images.neopets.com/items/mall_staff_jewelled.gif",
|
||||
},
|
||||
Object {
|
||||
"createdAt": "2020-01-01T00:00:00.000Z",
|
||||
"description": "Even the announcers of the Altador Cup celebrate. This was given out by the Advent Calendar in Y11.",
|
||||
"id": "48313",
|
||||
"isNc": false,
|
||||
"name": "Altador Cup Brooch",
|
||||
"rarityIndex": 101,
|
||||
"thumbnailUrl": "http://images.neopets.com/items/clo_altcuplogo_brooch.gif",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -33,6 +33,7 @@ jest.mock("../db");
|
|||
let dbExecuteFn;
|
||||
let db;
|
||||
let dbEnvironment = "production";
|
||||
let dbSetupDone = false;
|
||||
const dbSetupScripts = [
|
||||
fs
|
||||
.readFileSync(
|
||||
|
@ -60,15 +61,20 @@ beforeAll(() => {
|
|||
|
||||
db = await actualConnectToDb(options);
|
||||
|
||||
if (dbEnvironment === "test") {
|
||||
if (dbEnvironment === "test" && !dbSetupDone) {
|
||||
for (const script of dbSetupScripts) {
|
||||
await db.query(script);
|
||||
}
|
||||
}
|
||||
dbSetupDone = true;
|
||||
|
||||
dbExecuteFn = jest.spyOn(db, "execute");
|
||||
return db;
|
||||
});
|
||||
|
||||
// Mock out a current "now" date, for consistent snapshots
|
||||
const NOW = new Date("2020-01-01T00:00:00.000Z");
|
||||
jest.spyOn(global, "Date").mockImplementation(() => NOW);
|
||||
});
|
||||
beforeEach(() => {
|
||||
accessTokenForQueries = null;
|
||||
|
@ -76,11 +82,13 @@ beforeEach(() => {
|
|||
dbExecuteFn.mockClear();
|
||||
}
|
||||
dbEnvironment = "production";
|
||||
dbSetupDone = false;
|
||||
});
|
||||
afterAll(() => {
|
||||
if (db) {
|
||||
db.end();
|
||||
}
|
||||
Date.mockRestore();
|
||||
});
|
||||
const getDbCalls = () => (dbExecuteFn ? dbExecuteFn.mock.calls : []);
|
||||
const clearDbCalls = () => dbExecuteFn?.mockClear();
|
||||
|
@ -130,6 +138,7 @@ module.exports = {
|
|||
query,
|
||||
getDbCalls,
|
||||
clearDbCalls,
|
||||
getDb: () => db,
|
||||
useTestDb,
|
||||
logInAsTestUser,
|
||||
};
|
||||
|
|
|
@ -46,11 +46,30 @@ const resolvers = {
|
|||
},
|
||||
Query: {
|
||||
outfit: (_, { id }) => ({ id }),
|
||||
petOnNeopetsDotCom: async (_, { petName }) => {
|
||||
const [petMetaData, customPetData] = await Promise.all([
|
||||
loadPetMetaData(petName),
|
||||
loadCustomPetData(petName),
|
||||
petOnNeopetsDotCom: async (
|
||||
_,
|
||||
{ petName },
|
||||
{ db, itemLoader, itemTranslationLoader }
|
||||
) => {
|
||||
// Start all these requests as soon as possible...
|
||||
const petMetaDataPromise = loadPetMetaData(petName);
|
||||
const customPetDataPromise = loadCustomPetData(petName);
|
||||
const modelingPromise = customPetDataPromise.then((customPetData) =>
|
||||
saveModelingData(customPetData, {
|
||||
db,
|
||||
itemLoader,
|
||||
itemTranslationLoader,
|
||||
})
|
||||
);
|
||||
|
||||
// ...then wait on all of them before finishing. It's important to wait
|
||||
// on modeling, so that it doesn't get cut off when the request ends!
|
||||
const [petMetaData, customPetData, __] = await Promise.all([
|
||||
petMetaDataPromise,
|
||||
customPetDataPromise,
|
||||
modelingPromise,
|
||||
]);
|
||||
|
||||
const outfit = {
|
||||
// TODO: This isn't a fully-working Outfit object. It works for the
|
||||
// client as currently implemented, but we'll probably want to
|
||||
|
@ -66,6 +85,7 @@ const resolvers = {
|
|||
rarityIndex: o.rarity_index,
|
||||
})),
|
||||
};
|
||||
|
||||
return outfit;
|
||||
},
|
||||
},
|
||||
|
@ -131,4 +151,137 @@ function getPoseFromPetData(petMetaData, petCustomData) {
|
|||
}
|
||||
}
|
||||
|
||||
async function saveModelingData(
|
||||
customPetData,
|
||||
{ db, itemLoader, itemTranslationLoader }
|
||||
) {
|
||||
const itemIds = Object.keys(customPetData.object_info_registry);
|
||||
const [items, itemTranslations] = await Promise.all([
|
||||
itemLoader.loadMany(itemIds),
|
||||
itemTranslationLoader.loadMany(itemIds),
|
||||
]);
|
||||
|
||||
const rowsToInsert = [];
|
||||
const rowsToUpdate = [];
|
||||
for (const index in itemIds) {
|
||||
const itemId = itemIds[index];
|
||||
const item = items[index];
|
||||
const itemTranslation = itemTranslations[index];
|
||||
|
||||
const objectInfo = customPetData.object_info_registry[itemId];
|
||||
const objectInfoFields = {
|
||||
id: itemId,
|
||||
zonesRestrict: objectInfo.zones_restrict,
|
||||
thumbnailUrl: objectInfo.thumbnail_url,
|
||||
category: objectInfo.category,
|
||||
type: objectInfo.type,
|
||||
rarityIndex: objectInfo.rarity_index,
|
||||
price: objectInfo.price,
|
||||
weightLbs: objectInfo.weight_lbs,
|
||||
name: objectInfo.name,
|
||||
description: objectInfo.description,
|
||||
rarity: objectInfo.rarity,
|
||||
};
|
||||
|
||||
if (item instanceof Error) {
|
||||
// New item, we'll just insert it!
|
||||
rowsToInsert.push({
|
||||
...objectInfoFields,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const itemFields = {
|
||||
id: item.id,
|
||||
zonesRestrict: item.zonesRestrict,
|
||||
thumbnailUrl: item.thumbnailUrl,
|
||||
category: item.category,
|
||||
type: item.type,
|
||||
rarityIndex: item.rarityIndex,
|
||||
price: item.price,
|
||||
weightLbs: item.weightLbs,
|
||||
name: itemTranslation.name,
|
||||
description: itemTranslation.description,
|
||||
rarity: itemTranslation.rarity,
|
||||
};
|
||||
|
||||
if (objectsShallowEqual(objectInfoFields, itemFields)) {
|
||||
// Existing item, no change!
|
||||
continue;
|
||||
}
|
||||
|
||||
// Updated item, so we'll update it!
|
||||
rowsToUpdate.push({
|
||||
...objectInfoFields,
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
}
|
||||
|
||||
if (rowsToInsert.length > 0) {
|
||||
const itemQs = rowsToInsert
|
||||
.map((_) => "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
.join(", ");
|
||||
const itemTranslationQs = rowsToInsert
|
||||
.map((_) => "(?, ?, ?, ?, ?, ?, ?)")
|
||||
.join(", ");
|
||||
const itemValues = rowsToInsert.map((row) => [
|
||||
row.id,
|
||||
row.zonesRestrict,
|
||||
row.thumbnailUrl,
|
||||
row.category,
|
||||
row.type,
|
||||
row.rarityIndex,
|
||||
row.price,
|
||||
row.weightLbs,
|
||||
row.createdAt,
|
||||
row.updatedAt,
|
||||
]);
|
||||
const itemTranslationValues = rowsToInsert.map((row) => [
|
||||
row.id,
|
||||
"en",
|
||||
row.name,
|
||||
row.description,
|
||||
row.rarity,
|
||||
row.createdAt,
|
||||
row.updatedAt,
|
||||
]);
|
||||
|
||||
// NOTE: Hmm, I tried to use multiple statements to combine these, but I
|
||||
// guess it doesn't work for prepared statements?
|
||||
await Promise.all([
|
||||
db.execute(
|
||||
`INSERT INTO items
|
||||
(
|
||||
id, zones_restrict, thumbnail_url, category, type, rarity_index,
|
||||
price, weight_lbs, created_at, updated_at
|
||||
)
|
||||
VALUES ${itemQs};
|
||||
`,
|
||||
itemValues.flat()
|
||||
),
|
||||
db.execute(
|
||||
`INSERT INTO item_translations
|
||||
(item_id, locale, name, description, rarity, created_at, updated_at)
|
||||
VALUES ${itemTranslationQs};`,
|
||||
itemTranslationValues.flat()
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
// TODO: Update the items that need updating!
|
||||
}
|
||||
|
||||
/** Given two objects with the same keys, return whether their values match. */
|
||||
function objectsShallowEqual(a, b) {
|
||||
for (const key in a) {
|
||||
if (a[key] !== b[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = { typeDefs, resolvers };
|
||||
|
|
Loading…
Reference in a new issue