manifold/web/lib/api/graphql/resolvers/market.ts
joy_void_joy 85746f0461 graphql: Add slug, market and markets queries
Translate /api/v0/markets, /api/v0/market/[id] and /api/v0/slug/[id]
into their graphql equivalent
2022-07-20 18:15:56 +02:00

123 lines
3.3 KiB
TypeScript

import type {
MarketAnswerResolvers,
MarketResolvers,
QueryResolvers,
Resolvers,
ResolversTypes,
} from 'web/generated/graphql_api'
import type { MarketModel } from '../types'
import { UserInputError } from 'apollo-server-micro'
function contractVerify(contract?: MarketModel) {
if (!contract) {
throw new UserInputError('Contract not found')
}
return contract
}
function augmentContract<T>(contract: MarketModel, l: T[]) {
return l.map((el) => ({
...el,
contract,
}))
}
const answerResolvers: MarketAnswerResolvers = {
creator: (answer) => ({
id: answer.userId,
name: answer.name,
username: answer.username,
avatarUrl: answer.avatarUrl,
}),
probability: (answer, _, { dataSources }) =>
dataSources.firebaseAPI.getOutcomeProbability(answer.contract, answer.id),
market: async (answer) => answer.contract,
}
const marketResolvers: MarketResolvers = {
url: async (contract) =>
`https://manifold.markets/${contract.creatorUsername}/${contract.slug}`,
creator: async (contract) => ({
id: contract.creatorId,
username: contract.creatorUsername,
name: contract.creatorName,
avatarUrl: contract.creatorAvatarUrl,
}),
outcome: async (contract: MarketModel, _, { dataSources }) => {
switch (contract.outcomeType) {
case 'BINARY':
return {
__typename: 'MarketOutcomeBinary',
probability: await dataSources.firebaseAPI.getProbability(contract),
} as ResolversTypes['MarketOutcomeBinary']
case 'FREE_RESPONSE':
return {
__typename: 'MarketOutcomeFreeResponse',
answers: augmentContract(contract, contract.answers),
} as ResolversTypes['MarketOutcomeFreeResponse']
case 'PSEUDO_NUMERIC':
case 'NUMERIC':
return {
__typename: 'MarketOutcomeNumeric',
min: contract.min,
max: contract.max,
} as ResolversTypes['MarketOutcomeNumeric']
}
},
pool: async (contract) => contract.pool.YES + contract.pool.NO || undefined,
closeTime: async (contract) =>
contract.resolutionTime && contract.closeTime
? Math.min(contract.resolutionTime, contract.closeTime)
: contract.closeTime,
bets: async (contract, _, { dataSources }) =>
augmentContract(
contract,
await dataSources.firebaseAPI.listAllBets(contract.id)
),
comments: async (contract, _, { dataSources }) =>
augmentContract(
contract,
await dataSources.firebaseAPI.listAllComments(contract.id)
),
}
const queryResolvers: QueryResolvers = {
markets: async (_, { before, limit }, { dataSources }) => {
if (limit < 1 || limit > 1000) {
throw new UserInputError('limit must be between 1 and 1000')
}
try {
return await dataSources.firebaseAPI.listAllContracts(limit, before)
} catch (e) {
throw new UserInputError(
'Failed to fetch markets (did you pass an invalid ID as the before parameter?)'
)
}
},
market: async (_, { id }, { dataSources }) =>
contractVerify(await dataSources.firebaseAPI.getContractFromID(id)),
slug: async (_, { url }, { dataSources }) =>
contractVerify(await dataSources.firebaseAPI.getContractFromSlug(url)),
}
const resolver: Resolvers = {
Query: queryResolvers,
Market: marketResolvers,
MarketAnswer: answerResolvers,
}
export default resolver