add isCommonlyUsedByItems to Zone
This is in preparation for hiding bio zone restrictions but showing item zone restrictions! I also refactor the build-cached-data script substantially, to run GraphQL against the server instead of a custom query.
This commit is contained in:
parent
8f9f1a14de
commit
3a6e3fac8e
5 changed files with 95 additions and 31 deletions
|
@ -1,41 +1,62 @@
|
||||||
// We run this on build to cache some stable database tables into the JS
|
// We run this on build to cache some stable database tables into the JS
|
||||||
// bundle!
|
// bundle!
|
||||||
|
require("honeycomb-beeline")({
|
||||||
|
writeKey: process.env["HONEYCOMB_WRITE_KEY"],
|
||||||
|
dataset:
|
||||||
|
process.env["NODE_ENV"] === "production"
|
||||||
|
? "Dress to Impress (2020)"
|
||||||
|
: "Dress to Impress (2020, dev)",
|
||||||
|
serviceName: "impress-2020-build-process",
|
||||||
|
});
|
||||||
const fs = require("fs").promises;
|
const fs = require("fs").promises;
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
|
const { ApolloServer } = require("apollo-server");
|
||||||
|
const { createTestClient } = require("apollo-server-testing");
|
||||||
|
const gql = require("graphql-tag");
|
||||||
|
|
||||||
const connectToDb = require("../src/server/db");
|
const connectToDb = require("../src/server/db");
|
||||||
const { normalizeRow } = require("../src/server/util");
|
const { config } = require("../src/server");
|
||||||
|
|
||||||
const cachedDataPath = path.join(__dirname, "..", "src", "app", "cached-data");
|
const cachedDataPath = path.join(__dirname, "..", "src", "app", "cached-data");
|
||||||
|
|
||||||
async function buildZonesCache(db) {
|
async function main() {
|
||||||
const [rows] = await db.query(
|
await fs.mkdir(cachedDataPath, { recursive: true });
|
||||||
`SELECT z.id, z.depth, zt.label FROM zones z ` +
|
|
||||||
`INNER JOIN zone_translations zt ON z.id = zt.zone_id ` +
|
// Check out this scrappy way of making a query against server code ^_^`
|
||||||
`WHERE locale = "en" ORDER BY z.id;`
|
const { query } = createTestClient(new ApolloServer(config));
|
||||||
);
|
const res = await query({
|
||||||
const entities = rows.map(normalizeRow);
|
query: gql`
|
||||||
|
query BuildCachedData {
|
||||||
|
allZones {
|
||||||
|
id
|
||||||
|
label
|
||||||
|
depth
|
||||||
|
isCommonlyUsedByItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
if (res.errors) {
|
||||||
|
for (const error of res.errors) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
throw new Error(`GraphQL request failed`);
|
||||||
|
}
|
||||||
|
|
||||||
const filePath = path.join(cachedDataPath, "zones.json");
|
const filePath = path.join(cachedDataPath, "zones.json");
|
||||||
fs.writeFile(filePath, JSON.stringify(entities, null, 4), "utf8");
|
await fs.writeFile(
|
||||||
|
filePath,
|
||||||
|
JSON.stringify(res.data.allZones, null, 4),
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
|
||||||
console.log(`📚 Wrote zones to ${path.relative(process.cwd(), filePath)}`);
|
console.log(`📚 Wrote zones to ${path.relative(process.cwd(), filePath)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
main()
|
||||||
const db = await connectToDb();
|
.catch((e) => {
|
||||||
await fs.mkdir(cachedDataPath, { recursive: true });
|
|
||||||
|
|
||||||
try {
|
|
||||||
await buildZonesCache(db);
|
|
||||||
} catch (e) {
|
|
||||||
db.close();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch((e) => {
|
|
||||||
console.error(e);
|
console.error(e);
|
||||||
process.exitCode = 1;
|
process.exit(1);
|
||||||
});
|
})
|
||||||
|
.then(() => process.exit());
|
||||||
|
|
|
@ -105,6 +105,15 @@ const typePolicies = {
|
||||||
const id = readField("id");
|
const id = readField("id");
|
||||||
return label || cachedZonesById.get(id)?.label || `Zone #${id}`;
|
return label || cachedZonesById.get(id)?.label || `Zone #${id}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isCommonlyUsedByItems: (isCommonlyUsedByItems, { readField }) => {
|
||||||
|
const id = readField("id");
|
||||||
|
return (
|
||||||
|
isCommonlyUsedByItems ||
|
||||||
|
cachedZonesById.get(id)?.isCommonlyUsedByItems ||
|
||||||
|
false
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const { gql, makeExecutableSchema } = require("apollo-server");
|
const { gql, makeExecutableSchema } = require("apollo-server");
|
||||||
import { addBeelineToSchema, beelinePlugin } from "./lib/beeline-graphql";
|
const { addBeelineToSchema, beelinePlugin } = require("./lib/beeline-graphql");
|
||||||
|
|
||||||
const connectToDb = require("./db");
|
const connectToDb = require("./db");
|
||||||
const buildLoaders = require("./loaders");
|
const buildLoaders = require("./loaders");
|
||||||
|
@ -177,6 +177,7 @@ const typeDefs = gql`
|
||||||
id: ID!
|
id: ID!
|
||||||
depth: Int!
|
depth: Int!
|
||||||
label: String!
|
label: String!
|
||||||
|
isCommonlyUsedByItems: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ItemSearchResult {
|
type ItemSearchResult {
|
||||||
|
@ -224,6 +225,7 @@ const typeDefs = gql`
|
||||||
allColors: [Color!]! @cacheControl(maxAge: 10800) # Cache for 3 hours (we might add more!)
|
allColors: [Color!]! @cacheControl(maxAge: 10800) # Cache for 3 hours (we might add more!)
|
||||||
allSpecies: [Species!]! @cacheControl(maxAge: 10800) # Cache for 3 hours (we might add more!)
|
allSpecies: [Species!]! @cacheControl(maxAge: 10800) # Cache for 3 hours (we might add more!)
|
||||||
allValidSpeciesColorPairs: [SpeciesColorPair!]! # deprecated
|
allValidSpeciesColorPairs: [SpeciesColorPair!]! # deprecated
|
||||||
|
allZones: [Zone!]!
|
||||||
item(id: ID!): Item
|
item(id: ID!): Item
|
||||||
items(ids: [ID!]!): [Item!]!
|
items(ids: [ID!]!): [Item!]!
|
||||||
itemSearch(query: String!): ItemSearchResult!
|
itemSearch(query: String!): ItemSearchResult!
|
||||||
|
@ -536,6 +538,15 @@ const resolvers = {
|
||||||
const zoneTranslation = await zoneTranslationLoader.load(id);
|
const zoneTranslation = await zoneTranslationLoader.load(id);
|
||||||
return zoneTranslation.label;
|
return zoneTranslation.label;
|
||||||
},
|
},
|
||||||
|
isCommonlyUsedByItems: async ({ id }, _, { zoneLoader }) => {
|
||||||
|
// Zone metadata marks item zones with types 2, 3, and 4. But also, in
|
||||||
|
// practice, the Biology Effects zone (type 1) has been used for a few
|
||||||
|
// items too. So, that's what we return true for!
|
||||||
|
const zone = await zoneLoader.load(id);
|
||||||
|
const isMarkedForItems = ["2", "3", "4"].includes(zone.typeId);
|
||||||
|
const isBiologyEffects = zone.id === "4";
|
||||||
|
return isMarkedForItems || isBiologyEffects;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Color: {
|
Color: {
|
||||||
name: async ({ id }, _, { colorTranslationLoader }) => {
|
name: async ({ id }, _, { colorTranslationLoader }) => {
|
||||||
|
@ -599,6 +610,10 @@ const resolvers = {
|
||||||
}));
|
}));
|
||||||
return allPairs;
|
return allPairs;
|
||||||
},
|
},
|
||||||
|
allZones: async (_, __, { zoneLoader }) => {
|
||||||
|
const zones = await zoneLoader.loadAll();
|
||||||
|
return zones.map(({ id }) => ({ id }));
|
||||||
|
},
|
||||||
item: (_, { id }) => ({ id }),
|
item: (_, { id }) => ({ id }),
|
||||||
items: (_, { ids }) => {
|
items: (_, { ids }) => {
|
||||||
return ids.map((id) => ({ id }));
|
return ids.map((id) => ({ id }));
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
const beeline = require("honeycomb-beeline");
|
const beeline = require("honeycomb-beeline");
|
||||||
const gql = require("graphql");
|
const gql = require("graphql");
|
||||||
|
|
||||||
export function addBeelineToSchema(schema) {
|
function addBeelineToSchema(schema) {
|
||||||
if (!beeline) return;
|
if (!beeline) return;
|
||||||
forEachField(schema, (field) => {
|
forEachField(schema, (field) => {
|
||||||
if (!field.resolve) return;
|
if (!field.resolve) return;
|
||||||
|
@ -68,7 +68,7 @@ const fieldsFor = (name, path) => ({
|
||||||
"graphql.key": path.split(".").pop(),
|
"graphql.key": path.split(".").pop(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const beelinePlugin = {
|
const beelinePlugin = {
|
||||||
requestDidStart() {
|
requestDidStart() {
|
||||||
const trace = beeline.startTrace();
|
const trace = beeline.startTrace();
|
||||||
return {
|
return {
|
||||||
|
@ -84,3 +84,8 @@ export const beelinePlugin = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addBeelineToSchema,
|
||||||
|
beelinePlugin,
|
||||||
|
};
|
||||||
|
|
|
@ -397,8 +397,8 @@ const buildPetStatesForPetTypeLoader = (db, loaders) =>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const buildZoneLoader = (db) =>
|
const buildZoneLoader = (db) => {
|
||||||
new DataLoader(async (ids) => {
|
const zoneLoader = new DataLoader(async (ids) => {
|
||||||
const qs = ids.map((_) => "?").join(",");
|
const qs = ids.map((_) => "?").join(",");
|
||||||
const [rows, _] = await db.execute(
|
const [rows, _] = await db.execute(
|
||||||
`SELECT * FROM zones WHERE id IN (${qs})`,
|
`SELECT * FROM zones WHERE id IN (${qs})`,
|
||||||
|
@ -415,6 +415,20 @@ const buildZoneLoader = (db) =>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
zoneLoader.loadAll = async () => {
|
||||||
|
const [rows, _] = await db.execute(`SELECT * FROM zones`);
|
||||||
|
const entities = rows.map(normalizeRow);
|
||||||
|
|
||||||
|
for (const zone of entities) {
|
||||||
|
zoneLoader.prime(zone.id, zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entities;
|
||||||
|
};
|
||||||
|
|
||||||
|
return zoneLoader;
|
||||||
|
};
|
||||||
|
|
||||||
const buildZoneTranslationLoader = (db) =>
|
const buildZoneTranslationLoader = (db) =>
|
||||||
new DataLoader(async (zoneIds) => {
|
new DataLoader(async (zoneIds) => {
|
||||||
const qs = zoneIds.map((_) => "?").join(",");
|
const qs = zoneIds.map((_) => "?").join(",");
|
||||||
|
|
Loading…
Reference in a new issue