From df71a16354469ab77bc67b55d43d2b1c95674220 Mon Sep 17 00:00:00 2001 From: Matchu Date: Sat, 3 Apr 2021 14:26:41 -0700 Subject: [PATCH] Add wakaValueText GQL field to items Again, I think I'm getting a bit ahead of myself :p Mostly I wanted to see if this architecture would work out! --- src/server/loaders.js | 25 +++++++++++++++++++++++++ src/server/types/Item.js | 15 +++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/server/loaders.js b/src/server/loaders.js index 4fd01ef..0f1b734 100644 --- a/src/server/loaders.js +++ b/src/server/loaders.js @@ -1,4 +1,5 @@ import DataLoader from "dataloader"; +import fetch from "node-fetch"; import { normalizeRow } from "./util"; const buildClosetListLoader = (db) => @@ -600,6 +601,29 @@ const buildItemTradesLoader = (db, loaders) => { cacheKeyFn: ({ itemId, isOwned }) => `${itemId}-${isOwned}` } ); +const buildItemWakaValueLoader = () => + new DataLoader(async (itemIds) => { + // This loader calls our /api/allWakaValues endpoint, to take advantage of + // the CDN caching. This helps us respond a bit faster than Google Sheets + // API would, and avoid putting pressure on our Google Sheets API quotas. + // (Some kind of internal memcache or process-level cache would be a more + // idiomatic solution in a monolith server environment!) + const url = + process.env.NODE_ENV === "production" + ? "https://impress-2020.openneo.net/api/allWakaValues" + : "http://localhost:3000/api/allWakaValues"; + const res = await fetch(url); + if (!res.ok) { + throw new Error( + `Error loading /api/allWakaValues: ${res.status} ${res.statusText}` + ); + } + + const allWakaValues = await res.json(); + + return itemIds.map((itemId) => allWakaValues[itemId]); + }); + const buildPetTypeLoader = (db, loaders) => new DataLoader(async (petTypeIds) => { const qs = petTypeIds.map((_) => "?").join(","); @@ -1213,6 +1237,7 @@ function buildLoaders(db) { ); loaders.itemAllOccupiedZonesLoader = buildItemAllOccupiedZonesLoader(db); loaders.itemTradesLoader = buildItemTradesLoader(db, loaders); + loaders.itemWakaValueLoader = buildItemWakaValueLoader(); loaders.petTypeLoader = buildPetTypeLoader(db, loaders); loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader( db, diff --git a/src/server/types/Item.js b/src/server/types/Item.js index e4a4605..0cb3a3c 100644 --- a/src/server/types/Item.js +++ b/src/server/types/Item.js @@ -25,6 +25,11 @@ const typeDefs = gql` # item was added so long ago that we don't have this field! createdAt: String + # This item's capsule trade value as text, according to wakaguide.com, as a + # human-readable string. Will be null if the value is not known, or if + # there's an error connecting to the data source. + wakaValueText: String + currentUserOwnsThis: Boolean! @cacheControl(scope: PRIVATE) currentUserWantsThis: Boolean! @cacheControl(scope: PRIVATE) @@ -249,6 +254,16 @@ const resolvers = { const item = await itemLoader.load(id); return item.createdAt && item.createdAt.toISOString(); }, + wakaValueText: async ({ id }, _, { itemWakaValueLoader }) => { + try { + const wakaValue = await itemWakaValueLoader.load(id); + return wakaValue.value; + } catch (e) { + console.error(`Error loading wakaValueText for item ${id}, skipping:`); + console.error(e); + return null; + } + }, currentUserOwnsThis: async ( { id },