diff --git a/package.json b/package.json index 17565f3..9fb07c4 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 > scripts/setup-mysql-dev-schema.sql", + "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", "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 ba7d6f8..b31399b 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-18 6:27:12 +-- Dump completed on 2020-09-19 2:56:30 diff --git a/scripts/setup-mysql-dev-schema.sql b/scripts/setup-mysql-dev-schema.sql index ea3fb0f..458c378 100644 --- a/scripts/setup-mysql-dev-schema.sql +++ b/scripts/setup-mysql-dev-schema.sql @@ -65,7 +65,36 @@ CREATE TABLE `item_translations` ( KEY `index_item_translations_on_locale` (`locale`), KEY `index_item_translations_name` (`name`), KEY `index_item_translations_on_item_id_and_locale` (`item_id`,`locale`) -) ENGINE=InnoDB AUTO_INCREMENT=215758 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=215780 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `swf_assets` +-- + +DROP TABLE IF EXISTS `swf_assets`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `swf_assets` ( + `type` varchar(7) COLLATE utf8_unicode_ci NOT NULL, + `remote_id` mediumint(9) NOT NULL, + `url` mediumtext COLLATE utf8_unicode_ci NOT NULL, + `zone_id` tinyint(4) NOT NULL, + `zones_restrict` text COLLATE utf8_unicode_ci NOT NULL, + `created_at` datetime NOT NULL, + `body_id` smallint(6) NOT NULL, + `has_image` tinyint(1) NOT NULL DEFAULT '0', + `image_requested` tinyint(1) NOT NULL DEFAULT '0', + `reported_broken_at` datetime DEFAULT NULL, + `converted_at` datetime DEFAULT NULL, + `id` int(11) NOT NULL AUTO_INCREMENT, + `image_manual` tinyint(1) NOT NULL DEFAULT '0', + `manifest` text COLLATE utf8_unicode_ci, + PRIMARY KEY (`id`), + KEY `swf_assets_body_id_and_object_id` (`body_id`), + KEY `idx_swf_assets_zone_id` (`zone_id`), + KEY `swf_assets_type_and_id` (`type`,`remote_id`) +) ENGINE=InnoDB AUTO_INCREMENT=521790 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; @@ -77,4 +106,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 6:27:15 +-- Dump completed on 2020-09-19 2:56:34 diff --git a/src/server/loaders.js b/src/server/loaders.js index 5d713e0..2837bd0 100644 --- a/src/server/loaders.js +++ b/src/server/loaders.js @@ -385,6 +385,29 @@ const buildSwfAssetLoader = (db) => ); }); +const buildSwfAssetByRemoteIdLoader = (db) => + new DataLoader( + async (typeAndRemoteIdPairs) => { + const qs = typeAndRemoteIdPairs + .map((_) => "(type = ? AND remote_id = ?)") + .join(" OR "); + const values = typeAndRemoteIdPairs + .map(({ type, remoteId }) => [type, remoteId]) + .flat(); + const [rows, _] = await db.execute( + `SELECT * FROM swf_assets WHERE ${qs}`, + values + ); + + const entities = rows.map(normalizeRow); + + return swfAssetIds.map((remoteId) => + entities.find((e) => e.remoteId === remoteId) + ); + }, + { cacheKeyFn: ({ type, remoteId }) => `${type},${remoteId}` } + ); + const buildItemSwfAssetLoader = (db, loaders) => new DataLoader( async (itemAndBodyPairs) => { @@ -677,6 +700,7 @@ function buildLoaders(db) { loaders ); loaders.swfAssetLoader = buildSwfAssetLoader(db); + loaders.swfAssetByRemoteIdLoader = buildSwfAssetByRemoteIdLoader(db); loaders.itemSwfAssetLoader = buildItemSwfAssetLoader(db, loaders); loaders.petSwfAssetLoader = buildPetSwfAssetLoader(db, loaders); loaders.outfitLoader = buildOutfitLoader(db); diff --git a/src/server/query-tests/__snapshots__/Pet.test.js.snap b/src/server/query-tests/__snapshots__/Pet.test.js.snap index 7a30925..6040dc3 100644 --- a/src/server/query-tests/__snapshots__/Pet.test.js.snap +++ b/src/server/query-tests/__snapshots__/Pet.test.js.snap @@ -183,6 +183,27 @@ Array [ "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 = ?)", + Array [ + "object", + "6829", + "object", + "14855", + "object", + "14856", + "object", + "14857", + "object", + "36414", + "object", + "39646", + "object", + "51959", + "object", + "56478", + ], + ], Array [ "INSERT INTO items (category, created_at, id, price, rarity_index, thumbnail_url, type, updated_at, weight_lbs, zones_restrict) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", Array [ @@ -329,6 +350,67 @@ Array [ 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, + "6829", + "object", + "http://images.neopets.com/cp/items/swf/000/000/006/6829_1707e50385.swf", + 3, + "", + 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, + "", + ], + ], ] `; @@ -470,6 +552,27 @@ Array [ "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 = ?)", + Array [ + "object", + "6829", + "object", + "14855", + "object", + "14856", + "object", + "14857", + "object", + "36414", + "object", + "39646", + "object", + "51959", + "object", + "56478", + ], + ], Array [ "INSERT INTO items (category, created_at, id, price, rarity_index, thumbnail_url, type, updated_at, weight_lbs, zones_restrict) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", Array [ @@ -599,6 +702,67 @@ Array [ 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, + "6829", + "object", + "http://images.neopets.com/cp/items/swf/000/000/006/6829_1707e50385.swf", + 3, + "", + 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, + "", + ], + ], Array [ "UPDATE items SET rarity_index = ?, thumbnail_url = ?, updated_at = ?, zones_restrict = ? WHERE id = ?;", Array [ diff --git a/src/server/types/Outfit.js b/src/server/types/Outfit.js index dbbf08e..769ce35 100644 --- a/src/server/types/Outfit.js +++ b/src/server/types/Outfit.js @@ -49,7 +49,7 @@ const resolvers = { petOnNeopetsDotCom: async ( _, { petName }, - { db, itemLoader, itemTranslationLoader } + { db, itemLoader, itemTranslationLoader, swfAssetByRemoteIdLoader } ) => { // Start all these requests as soon as possible... const petMetaDataPromise = loadPetMetaData(petName); @@ -59,6 +59,7 @@ const resolvers = { db, itemLoader, itemTranslationLoader, + swfAssetByRemoteIdLoader, }) ); @@ -153,9 +154,10 @@ function getPoseFromPetData(petMetaData, petCustomData) { async function saveModelingData( customPetData, - { db, itemLoader, itemTranslationLoader } + { db, itemLoader, itemTranslationLoader, swfAssetByRemoteIdLoader } ) { const objectInfos = Object.values(customPetData.object_info_registry); + const objectAssets = Object.values(customPetData.object_asset_registry); const incomingItems = objectInfos.map((objectInfo) => ({ id: String(objectInfo.obj_info_id), @@ -176,6 +178,18 @@ async function saveModelingData( rarity: objectInfo.rarity, })); + const incomingItemSwfAssets = objectAssets.map((objectAsset) => ({ + type: "object", + remoteId: String(objectAsset.asset_id), + url: objectAsset.asset_url, + zoneId: 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: customPetData.custom_pet.body_id, + })); + await Promise.all([ syncToDb(db, incomingItems, { loader: itemLoader, @@ -192,6 +206,17 @@ async function saveModelingData( row.itemId, ], }), + syncToDb(db, incomingItemSwfAssets, { + loader: swfAssetByRemoteIdLoader, + tableName: "swf_assets", + buildLoaderKey: (row) => ({ type: row.type, remoteId: row.remoteId }), + buildUpdateCondition: (row) => [ + `type = ? AND remote_id = ?`, + row.type, + row.remoteId, + ], + includeUpdatedAt: false, + }), ]); } @@ -210,7 +235,14 @@ async function saveModelingData( async function syncToDb( db, incomingRows, - { loader, tableName, buildLoaderKey, buildUpdateCondition } + { + loader, + tableName, + buildLoaderKey, + buildUpdateCondition, + includeCreatedAt = true, + includeUpdatedAt = true, + } ) { const loaderKeys = incomingRows.map(buildLoaderKey); const currentRows = await loader.loadMany(loaderKeys); @@ -223,11 +255,14 @@ async function syncToDb( // If there is no corresponding row in the database, prepare an insert. if (currentRow instanceof Error) { - inserts.push({ - ...incomingRow, - createdAt: new Date(), - updatedAt: new Date(), - }); + const insert = { ...incomingRow }; + if (includeCreatedAt) { + insert.createdAt = new Date(); + } + if (includeUpdatedAt) { + insert.updatedAt = new Date(); + } + inserts.push(insert); continue; } @@ -241,7 +276,9 @@ async function syncToDb( for (const key of updatedKeys) { update[key] = incomingRow[key]; } - update.updatedAt = new Date(); + if (includeUpdatedAt) { + update.updatedAt = new Date(); + } updates.push({ incomingRow, update }); } }