79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
import { guesstimate } from "../../backend/platforms/guesstimate";
|
|
import { AlgoliaQuestion } from "../../backend/utils/algolia";
|
|
import searchWithAlgolia from "../../web/worker/searchWithAlgolia";
|
|
import { builder } from "../builder";
|
|
import { QuestionObj } from "./questions";
|
|
|
|
const SearchInput = builder.inputType("SearchInput", {
|
|
fields: (t) => ({
|
|
query: t.string({ required: true }),
|
|
starsThreshold: t.int({
|
|
description: "Minimum number of stars on a question",
|
|
}),
|
|
forecastsThreshold: t.int({
|
|
description: "Minimum number of forecasts on a question",
|
|
}),
|
|
forecastingPlatforms: t.stringList({
|
|
description: "List of platform ids to filter by",
|
|
}),
|
|
limit: t.int(),
|
|
}),
|
|
});
|
|
|
|
builder.queryField("searchQuestions", (t) =>
|
|
t.field({
|
|
type: [QuestionObj],
|
|
description:
|
|
"Search for questions; uses Algolia instead of the primary metaforecast database",
|
|
args: {
|
|
input: t.arg({ type: SearchInput, required: true }),
|
|
},
|
|
resolve: async (parent, { input }) => {
|
|
// defs
|
|
const query = input.query === undefined ? "" : input.query;
|
|
if (query === "") return [];
|
|
const { forecastsThreshold, starsThreshold } = input;
|
|
|
|
const platformsIncludeGuesstimate =
|
|
input.forecastingPlatforms?.includes("guesstimate") &&
|
|
(!starsThreshold || starsThreshold <= 1);
|
|
|
|
// preparation
|
|
const unawaitedAlgoliaResponse = searchWithAlgolia({
|
|
queryString: query,
|
|
hitsPerPage: input.limit ?? 50,
|
|
starsThreshold: starsThreshold ?? undefined,
|
|
filterByPlatforms: input.forecastingPlatforms ?? undefined,
|
|
forecastsThreshold: forecastsThreshold ?? undefined,
|
|
});
|
|
|
|
let results: AlgoliaQuestion[] = [];
|
|
|
|
// consider the guesstimate and the non-guesstimate cases separately.
|
|
if (platformsIncludeGuesstimate) {
|
|
const [responsesNotGuesstimate, responsesGuesstimate] =
|
|
await Promise.all([
|
|
unawaitedAlgoliaResponse,
|
|
guesstimate.search(query),
|
|
]); // faster than two separate requests
|
|
results = [...responsesNotGuesstimate, ...responsesGuesstimate];
|
|
} else {
|
|
results = await unawaitedAlgoliaResponse;
|
|
}
|
|
|
|
return results.map((q) => ({
|
|
...q,
|
|
fetched: new Date(
|
|
q.fetched || q.timestamp || new Date().toISOString() // q.timestamp is deprecated, TODO - just use `q.fetched`
|
|
),
|
|
timestamp: new Date(
|
|
q.fetched || q.timestamp || new Date().toISOString()
|
|
),
|
|
firstSeen: new Date(
|
|
q.firstSeen || new Date().toISOString() // TODO - q.firstSeen is not yet populated in algolia
|
|
),
|
|
}));
|
|
},
|
|
})
|
|
);
|