Skip to content

Commit

Permalink
Merge pull request #133 from moeyashi/feature/132
Browse files Browse the repository at this point in the history
Feature/132
  • Loading branch information
moeyashi authored May 25, 2024
2 parents bc77842 + 4b354ad commit 8e70401
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 1 deletion.
17 changes: 17 additions & 0 deletions src/infra/repository/nita.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,22 @@ export const postgresNitaRepository = () => {
`;
return Number(results[0].count);
},
async selectRival(executorDiscordId, rivalDiscordId) {
const results = await sql`
SELECT
nita1.track_code,
nita1.milliseconds AS executor_milliseconds,
nita2.milliseconds AS rival_milliseconds
FROM (SELECT * FROM nita WHERE discord_user_id = ${executorDiscordId}) AS nita1
INNER JOIN (SELECT * FROM nita WHERE discord_user_id = ${rivalDiscordId}) AS nita2
ON nita1.track_code = nita2.track_code
ORDER BY nita1.milliseconds - nita2.milliseconds
`;
return results.map((row) => ({
trackCode: row.track_code,
executorMilliseconds: row.executor_milliseconds,
rivalMilliseconds: row.rival_milliseconds,
}));
},
};
};
73 changes: 73 additions & 0 deletions src/slash-command/rival.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// @ts-check
import { SlashCommandBuilder } from 'discord.js';
import { searchTrack } from '../const/track.js';
import { displayMilliseconds } from '../util/time.js';

/** @type { import('../types').SlashCommand } */
export default {
data: new SlashCommandBuilder()
.setName('rival')
.setDescription('サーバー内のユーザーと記録を比較します')
.addUserOption((option) =>
option.setName('rival').setDescription('比較対象').setRequired(true),
),
execute: async (interaction, nitaRepository) => {
if (!interaction.guild) {
if (!interaction.inGuild()) {
throw new Error(
'サーバー内で実行してください。rivalコマンドはDMやグループDMでは実行できません。',
);
}
// https://github.com/discordjs/discord.js/blob/main/packages/discord.js/src/structures/BaseInteraction.js#L180-L182
// https://github.com/moeyashi/discord-mk8d-nita-record/issues/78
// https://scrapbox.io/discordjs-japan/%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%BC%E3%81%8B%E3%82%89%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B
// interaction.guildはキャッシュから取得しているしているため、interaction.guildがfalsyでinteraction.guildIdがtruthyの場合はfetchして取得する
await interaction.client.guilds.fetch(interaction.guildId);
if (!interaction.guild) {
throw new Error(
'不明なエラー:サーバーが見つかりませんでした。スクショして連絡してもらえたらありがたいです!',
);
}
}

const userQuery = interaction.options.getUser('rival');
if (!userQuery) {
throw new Error('比較対象を指定してください');
}

await interaction.deferReply();

const tracks = await nitaRepository.selectRival(
interaction.user.id,
userQuery.id,
);
/** @type {import('discord.js').InteractionReplyOptions} */
const res = {
content: `VS ${userQuery.displayName || userQuery.username}`,
};
if (tracks.length === 0) {
res.content = res.content + '\n\n記録がありません';
} else {
/** @type {import('discord.js').APIEmbed[]} */
const embeds = [];
res.embeds = tracks.reduce(
(pv, { trackCode, executorMilliseconds, rivalMilliseconds }, i) => {
const track = searchTrack(trackCode);
if (i % 25 === 0) {
pv.push({
fields: [],
});
}
const diffRival = executorMilliseconds - rivalMilliseconds;
pv[pv.length - 1].fields?.push({
name: track?.trackName || '',
value: `${displayMilliseconds(executorMilliseconds)} VS ${displayMilliseconds(rivalMilliseconds)} ${diffRival / 1000}秒`,
});
return pv;
},
embeds,
);
}
await interaction.followUp(res);
},
};
7 changes: 6 additions & 1 deletion src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
ClientEvents,
GuildMember,
SlashCommandBuilder,
SlashCommandOptionsOnlyBuilder,
} from "discord.js";

export type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
Expand Down Expand Up @@ -38,6 +39,10 @@ export type NitaRepository = {
trackCode: string,
discordMembers: GuildMember[]
) => Promise<number>;
selectRival: (
executorDiscordId: string,
rivalDiscordId: string
) => Promise<{ trackCode: string; executorMilliseconds: number; rivalMilliseconds: number; }[]>;
};

// 参考 https://typescriptbook.jp/reference/functions/overload-functions#%E3%82%A2%E3%83%AD%E3%83%BC%E9%96%A2%E6%95%B0%E3%81%A8%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%AD%E3%83%BC%E3%83%89
Expand All @@ -53,7 +58,7 @@ export type Event<EventName extends EventType> = {
export type SlashCommand = {
data:
| SlashCommandBuilder
| Omit<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">;
| SlashCommandOptionsOnlyBuilder;
execute: (
interaction: ChatInputCommandInteraction<CacheType>,
nitaRepository: NitaRepository
Expand Down

0 comments on commit 8e70401

Please sign in to comment.