From ff3fc943d756748c2e7ae286694377cedd9e1017 Mon Sep 17 00:00:00 2001 From: Matchu Date: Sat, 19 Sep 2020 03:28:53 -0700 Subject: [PATCH] modeling saves pet type --- package.json | 2 +- scripts/setup-mysql-dev-constants.sql | 2 +- scripts/setup-mysql-dev-schema.sql | 22 +++++- src/server/query-tests/Pet.test.js | 14 +++- .../__snapshots__/Pet.test.js.snap | 48 ++++++++++- src/server/types/Outfit.js | 79 +++++++++++++------ src/server/types/PetAppearance.js | 3 + 7 files changed, 140 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 9fb07c4..a6144d8 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "mysql-dev": "mysql --host=localhost --user=impress_2020_dev --password=impress_2020_dev --database=impress_2020_dev", "mysql-admin": "mysql --host=impress.openneo.net --user=matchu --password --database=openneo_impress", "mysqldump": "mysqldump --host=impress.openneo.net --user=$(dotenv -p IMPRESS_MYSQL_USER) --password=$(dotenv -p IMPRESS_MYSQL_PASSWORD) --column-statistics=0", - "download-mysql-schema": "yarn --silent mysqldump openneo_impress species species_translations colors color_translations > scripts/setup-mysql-dev-constants.sql && yarn --silent mysqldump --no-data openneo_impress items item_translations swf_assets > scripts/setup-mysql-dev-schema.sql", + "download-mysql-schema": "yarn --silent mysqldump --no-data openneo_impress items item_translations pet_types pet_states swf_assets > scripts/setup-mysql-dev-schema.sql && yarn --silent mysqldump openneo_impress species species_translations colors color_translations > scripts/setup-mysql-dev-constants.sql", "setup-mysql": "yarn mysql-admin < scripts/setup-mysql.sql", "setup-mysql-dev": "yarn mysql-dev < scripts/setup-mysql-dev-constants.sql && yarn mysql-dev < scripts/setup-mysql-dev-schema.sql", "build-cached-data": "node -r dotenv/config scripts/build-cached-data.js", diff --git a/scripts/setup-mysql-dev-constants.sql b/scripts/setup-mysql-dev-constants.sql index b31399b..edf4a25 100644 --- a/scripts/setup-mysql-dev-constants.sql +++ b/scripts/setup-mysql-dev-constants.sql @@ -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-19 2:56:30 +-- Dump completed on 2020-09-19 3:12:59 diff --git a/scripts/setup-mysql-dev-schema.sql b/scripts/setup-mysql-dev-schema.sql index 458c378..ee50b72 100644 --- a/scripts/setup-mysql-dev-schema.sql +++ b/scripts/setup-mysql-dev-schema.sql @@ -68,6 +68,26 @@ CREATE TABLE `item_translations` ( ) ENGINE=InnoDB AUTO_INCREMENT=215780 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `pet_types` +-- + +DROP TABLE IF EXISTS `pet_types`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `pet_types` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `color_id` tinyint(4) NOT NULL, + `species_id` tinyint(4) NOT NULL, + `created_at` datetime NOT NULL, + `body_id` smallint(6) NOT NULL, + `image_hash` varchar(8) COLLATE utf8_unicode_ci DEFAULT NULL, + `basic_image_hash` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `pet_types_species_color` (`species_id`,`color_id`) +) ENGINE=InnoDB AUTO_INCREMENT=4795 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `swf_assets` -- @@ -106,4 +126,4 @@ CREATE TABLE `swf_assets` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2020-09-19 2:56:34 +-- Dump completed on 2020-09-19 3:12:53 diff --git a/src/server/query-tests/Pet.test.js b/src/server/query-tests/Pet.test.js index eced112..9233a12 100644 --- a/src/server/query-tests/Pet.test.js +++ b/src/server/query-tests/Pet.test.js @@ -57,7 +57,7 @@ describe("Pet", () => { `); }); - it("models new item data", async () => { + it("models new pet and item data", async () => { useTestDb(); const res = await query({ @@ -86,6 +86,18 @@ describe("Pet", () => { const res2 = await query({ query: gql` query { + petAppearance(colorId: "75", speciesId: "54", pose: SAD_MASC) { + id + pose + layers { + id + swfUrl + } + restrictedZones { + id + } + } + items( ids: [ "37229" diff --git a/src/server/query-tests/__snapshots__/Pet.test.js.snap b/src/server/query-tests/__snapshots__/Pet.test.js.snap index 6040dc3..71143a8 100644 --- a/src/server/query-tests/__snapshots__/Pet.test.js.snap +++ b/src/server/query-tests/__snapshots__/Pet.test.js.snap @@ -82,7 +82,7 @@ Object { } `; -exports[`Pet models new item data 1`] = ` +exports[`Pet models new pet and item data 1`] = ` Object { "petOnNeopetsDotCom": Object { "items": Array [ @@ -155,8 +155,15 @@ Object { } `; -exports[`Pet models new item data 2`] = ` +exports[`Pet models new pet and item data 2`] = ` Array [ + Array [ + "SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)", + Array [ + "54", + "75", + ], + ], Array [ "SELECT * FROM items WHERE id IN (?,?,?,?,?,?,?,?)", Array [ @@ -204,6 +211,15 @@ Array [ "56478", ], ], + 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 [ @@ -414,7 +430,7 @@ Array [ ] `; -exports[`Pet models new item data 3`] = ` +exports[`Pet models new pet and item data 3`] = ` Object { "items": Array [ Object { @@ -490,11 +506,19 @@ Object { "thumbnailUrl": "http://images.neopets.com/items/clo_altcuplogo_brooch.gif", }, ], + "petAppearance": null, } `; -exports[`Pet models new item data 4`] = ` +exports[`Pet models new pet and item data 4`] = ` Array [ + Array [ + "SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)", + Array [ + "54", + "75", + ], + ], Array [ "SELECT * FROM item_translations WHERE item_id IN (?,?,?,?,?,?,?,?) AND locale = \\"en\\"", Array [ @@ -526,6 +550,13 @@ Array [ exports[`Pet models updated item data 1`] = ` Array [ + Array [ + "SELECT * FROM pet_types WHERE (species_id = ? AND color_id = ?)", + Array [ + "54", + "75", + ], + ], Array [ "SELECT * FROM items WHERE id IN (?,?,?,?,?,?,?,?)", Array [ @@ -573,6 +604,15 @@ Array [ "56478", ], ], + 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 [ diff --git a/src/server/types/Outfit.js b/src/server/types/Outfit.js index 769ce35..d533598 100644 --- a/src/server/types/Outfit.js +++ b/src/server/types/Outfit.js @@ -49,28 +49,27 @@ const resolvers = { petOnNeopetsDotCom: async ( _, { petName }, - { db, itemLoader, itemTranslationLoader, swfAssetByRemoteIdLoader } + { + db, + petTypeBySpeciesAndColorLoader, + itemLoader, + itemTranslationLoader, + swfAssetByRemoteIdLoader, + } ) => { - // 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, - swfAssetByRemoteIdLoader, - }) - ); - - // ...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 [customPetData, petMetaData, __] = await Promise.all([ + loadCustomPetData(petName), + loadPetMetaData(petName), ]); + await saveModelingData(customPetData, petMetaData, { + db, + petTypeBySpeciesAndColorLoader, + itemLoader, + itemTranslationLoader, + swfAssetByRemoteIdLoader, + }); + 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 @@ -154,8 +153,16 @@ function getPoseFromPetData(petMetaData, petCustomData) { async function saveModelingData( customPetData, - { db, itemLoader, itemTranslationLoader, swfAssetByRemoteIdLoader } + petMetaData, + { + db, + petTypeBySpeciesAndColorLoader, + itemLoader, + itemTranslationLoader, + swfAssetByRemoteIdLoader, + } ) { + const customPet = customPetData.custom_pet; const objectInfos = Object.values(customPetData.object_info_registry); const objectAssets = Object.values(customPetData.object_asset_registry); @@ -187,10 +194,37 @@ async function saveModelingData( // 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: customPetData.custom_pet.body_id, + bodyId: customPet.body_id, })); + const incomingPetTypes = [ + { + colorId: String(customPet.color_id), + speciesId: String(customPet.species_id), + bodyId: String(customPet.body_id), + // NOTE: I skip the image_hash stuff here... on Rails, we set a hash on + // creation, and may or may not bother to update it, I forget? But + // here I don't want to bother with an update. We could maybe do + // a merge function to make it on create only, but eh, I don't + // care enough ^_^` + }, + ]; + await Promise.all([ + syncToDb(db, incomingPetTypes, { + loader: petTypeBySpeciesAndColorLoader, + tableName: "pet_types", + buildLoaderKey: (row) => ({ + speciesId: row.speciesId, + colorId: row.colorId, + }), + buildUpdateCondition: (row) => [ + `species_id = ? AND color_id = ?`, + row.speciesId, + row.colorId, + ], + includeUpdatedAt: false, + }), syncToDb(db, incomingItems, { loader: itemLoader, tableName: "items", @@ -254,7 +288,8 @@ async function syncToDb( const currentRow = currentRows[index]; // If there is no corresponding row in the database, prepare an insert. - if (currentRow instanceof Error) { + // TODO: Should probably converge on whether not-found is null or an error + if (currentRow == null || currentRow instanceof Error) { const insert = { ...incomingRow }; if (includeCreatedAt) { insert.createdAt = new Date(); diff --git a/src/server/types/PetAppearance.js b/src/server/types/PetAppearance.js index 7bc9233..b804b05 100644 --- a/src/server/types/PetAppearance.js +++ b/src/server/types/PetAppearance.js @@ -208,6 +208,9 @@ const resolvers = { speciesId, colorId, }); + if (!petType) { + return null; + } // TODO: We could query for this more directly, instead of loading all // appearances 🤔