Skip to content

Commit

Permalink
chore(market): isolate as much logic as possible (#54)
Browse files Browse the repository at this point in the history
* chore(market): isolate as much logic as possible

* chore: codacy style fix
  • Loading branch information
karashiiro authored May 16, 2022
1 parent 3721c57 commit 8faa2bf
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 52 deletions.
65 changes: 14 additions & 51 deletions modules/venat-module-xiv-market/src/commands/market.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import {
} from '@discord-nestjs/core';
import { Logger } from '@nestjs/common';
import { InteractionReplyOptions, MessageEmbed } from 'discord.js';
import { getMarketListings } from '../data/universalis';
import { getMarketInfo } from '../data/universalis';
import { getItemIdByName } from '../data/xivapi';
import { table } from 'table';
import { MarketDto } from '../dto/market.dto';
import { buildTextTable, getMarketInfoByName } from '../data/listings';

@Command({
description: 'Look up prices for an item on the market board.',
Expand All @@ -23,58 +23,21 @@ export class MarketCommand implements DiscordTransformedCommand<MarketDto> {
public async handler(
@Payload() dto: MarketDto,
): Promise<InteractionReplyOptions> {
const itemLookup = await getItemIdByName(dto.item);
if (itemLookup.err != null) {
this.logger.error(itemLookup.err.message, itemLookup.err.stack);
return {
content: 'Failed to access XIVAPI; please try again later.',
};
const getMarketInfoPartial = getMarketInfoByName(
getItemIdByName,
getMarketInfo,
this.logger.error,
);
const marketInfo = await getMarketInfoPartial(dto.item, dto.server);
if (typeof marketInfo === 'string') {
return { content: marketInfo };
}

if (!itemLookup.success) {
return {
content:
'The item could not be found; please check your spelling and try again.',
};
}

const item = itemLookup.value;
const marketLookup = await getMarketListings(item.ID, dto.server);
if (marketLookup.err != null) {
this.logger.error(marketLookup.err.message, marketLookup.err.stack);
return {
content:
'The item could not be found; please check your spelling of the server and try again.',
};
}

if (!marketLookup.success) {
return {
content:
'The item could not be found; please check your spelling and try again.',
};
}

const { lastUploadTime, listings, worldName, dcName } = marketLookup.value;
const { lastUploadTime, listings, worldName, dcName, itemName } =
marketInfo;
const listingsEmbed = new MessageEmbed()
.setTitle(`Cheapest listings for ${item.Name} on ${dcName ?? worldName}`)
.setDescription(
'```' +
table([
['HQ', 'Unit Price', 'Quantity', 'Total', 'World'],
...listings
.sort((a, b) => a.pricePerUnit - b.pricePerUnit)
.slice(0, 10)
.map((l) => [
l.hq ? 'Yes' : 'No',
l.pricePerUnit.toLocaleString('en'),
l.quantity.toLocaleString('en'),
l.total.toLocaleString('en'),
worldName ?? l.worldName,
]),
]) +
'```',
)
.setTitle(`Cheapest listings for ${itemName} on ${dcName ?? worldName}`)
.setDescription('```' + buildTextTable(listings, worldName) + '```')
.setColor('#a58947')
.setFooter({
text: 'Last updated:',
Expand Down
81 changes: 81 additions & 0 deletions modules/venat-module-xiv-market/src/data/listings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { LookupResult } from '@the-convocation/venat-core';
import { table } from 'table';
import { UniversalisMarketInfo } from './universalis';
import { XIVAPIItem } from './xivapi';

export interface MarketListing {
pricePerUnit: number;
quantity: number;
total: number;
hq: boolean;
worldName?: string;
}

export interface MarketInfo {
itemId: number;
itemName: string;
worldName?: string;
dcName?: string;
lastUploadTime: number;
listings: MarketListing[];
}

export function buildTextTable(
listings: MarketListing[],
worldName?: string,
): string {
return table([
['HQ', 'Unit Price', 'Quantity', 'Total', 'World'],
...listings
.sort((a, b) => a.pricePerUnit - b.pricePerUnit)
.slice(0, 10)
.map((l) => [
l.hq ? 'Yes' : 'No',
l.pricePerUnit.toLocaleString('en'),
l.quantity.toLocaleString('en'),
l.total.toLocaleString('en'),
worldName ?? l.worldName,
]),
]);
}

export function getMarketInfoByName(
getItemIdByName: (itemName: string) => Promise<LookupResult<XIVAPIItem>>,
getMarketInfo: (
itemId: number,
server: string,
) => Promise<LookupResult<UniversalisMarketInfo>>,
logError: (message?: string, stack?: string) => void,
): (itemName: string, server: string) => Promise<MarketInfo | string> {
return async (
itemName: string,
server: string,
): Promise<MarketInfo | string> => {
const itemLookup = await getItemIdByName(itemName);
if (itemLookup.err != null) {
logError(itemLookup.err.message, itemLookup.err.stack);
return 'Failed to access XIVAPI; please try again later.';
}

if (!itemLookup.success) {
return 'The item could not be found; please check your spelling and try again.';
}

const item = itemLookup.value;
const marketLookup = await getMarketInfo(item.ID, server);
if (marketLookup.err != null) {
logError(marketLookup.err.message, marketLookup.err.stack);
return 'The item could not be found; please check your spelling of the server and try again.';
}

if (!marketLookup.success) {
return 'The item could not be found; please check your spelling and try again.';
}

return {
...marketLookup.value,
itemId: itemLookup.value.ID,
itemName: itemLookup.value.Name,
};
};
}
2 changes: 1 addition & 1 deletion modules/venat-module-xiv-market/src/data/universalis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface UniversalisMarketInfo {
dcName?: string;
}

export async function getMarketListings(
export async function getMarketInfo(
itemId: number,
server: string,
): Promise<LookupResult<UniversalisMarketInfo>> {
Expand Down

0 comments on commit 8faa2bf

Please sign in to comment.