From 26087f41571dbec92307dcae0fb6ae136ab5de43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SnO=E2=82=82WMaN?= Date: Mon, 27 Nov 2023 00:28:56 +0900 Subject: [PATCH] =?UTF-8?q?`calcMadCountGrowth`=E3=81=AE=E5=AE=9F=E8=A3=85?= =?UTF-8?q?=20(#952)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #950 --- package-lock.json | 15 +++++++++++++++ package.json | 1 + src/Video/Video.service.ts | 5 +++++ src/Video/calcMadCountGrowth.graphql | 18 ++++++++++++++++++ src/Video/calcMadCountGrowth.resolver.ts | 9 +++++++++ src/resolvers/Query/index.ts | 2 ++ src/resolvers/index.ts | 3 +++ src/utils/splitDate.test.ts | 12 ++++++++++++ src/utils/splitDate.ts | 5 +++++ 9 files changed, 70 insertions(+) create mode 100644 src/Video/calcMadCountGrowth.graphql create mode 100644 src/Video/calcMadCountGrowth.resolver.ts create mode 100644 src/utils/splitDate.test.ts create mode 100644 src/utils/splitDate.ts diff --git a/package-lock.json b/package-lock.json index 32e547d8..14d19a77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@prisma/client": "5.6.0", "auth0": "^3.3.0", "graphql": "^16.6.0", + "graphql-scalars": "^1.22.4", "graphql-tag": "^2.12.6", "graphql-yoga": "^5.0.0", "ioredis": "^5.3.1", @@ -6550,6 +6551,20 @@ "graphql": "14 - 16" } }, + "node_modules/graphql-scalars": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/graphql-scalars/-/graphql-scalars-1.22.4.tgz", + "integrity": "sha512-ILnv7jq5VKHLUyoaTFX7lgYrjCd6vTee9i8/B+D4zJKJT5TguOl0KkpPEbXHjmeor8AZYrVsrYUHdqRBMX1pjA==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, "node_modules/graphql-schema-linter": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/graphql-schema-linter/-/graphql-schema-linter-3.0.1.tgz", diff --git a/package.json b/package.json index dd84a729..0157fefa 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@prisma/client": "5.6.0", "auth0": "^3.3.0", "graphql": "^16.6.0", + "graphql-scalars": "^1.22.4", "graphql-tag": "^2.12.6", "graphql-yoga": "^5.0.0", "ioredis": "^5.3.1", diff --git a/src/Video/Video.service.ts b/src/Video/Video.service.ts index 436c0804..fd789941 100644 --- a/src/Video/Video.service.ts +++ b/src/Video/Video.service.ts @@ -10,6 +10,11 @@ export const mkVideoService = ({ prisma }: { prisma: PrismaClient }) => { countAll() { return prisma.video.count(); }, + async calcGrowth(dates: Date[]) { + return prisma + .$transaction(dates.map((lte) => prisma.video.count({ where: { createdAt: { lte } } }))) + .then((counts) => counts.map((count, i) => ({ count, date: dates[i] }))); + }, }; }; diff --git a/src/Video/calcMadCountGrowth.graphql b/src/Video/calcMadCountGrowth.graphql new file mode 100644 index 00000000..894cb625 --- /dev/null +++ b/src/Video/calcMadCountGrowth.graphql @@ -0,0 +1,18 @@ +type Query { + "一定区間の音MADの登録個数の時系列データを計算する" + calcMadCountGrowth(input: CalcMadCountGrowthInput!): [MadCountGrowth]! +} + +input CalcMadCountGrowthInput { + "開始日時" + start: DateTime! + "終了日時" + end: DateTime! + "何分割するか" + split: Int! +} + +type MadCountGrowth { + date: DateTime! + count: Int! +} diff --git a/src/Video/calcMadCountGrowth.resolver.ts b/src/Video/calcMadCountGrowth.resolver.ts new file mode 100644 index 00000000..e0eae355 --- /dev/null +++ b/src/Video/calcMadCountGrowth.resolver.ts @@ -0,0 +1,9 @@ +import { MkQueryResolver } from "../utils/MkResolver.js"; +import { splitDate } from "../utils/splitDate.js"; + +export const mkCalcMadCountGrowthResolver: MkQueryResolver<"calcMadCountGrowth", "VideoService"> = + ({ VideoService }) => + async (_parent, { input: { start, end, split } }) => { + const splits = splitDate(start, end, split); + return VideoService.calcGrowth(splits); + }; diff --git a/src/resolvers/Query/index.ts b/src/resolvers/Query/index.ts index 7eb8cc1c..ec1b7bd9 100644 --- a/src/resolvers/Query/index.ts +++ b/src/resolvers/Query/index.ts @@ -26,6 +26,7 @@ import { resolverSearchTags } from "../../Tag/searchTags.resolver.js"; import { mkShowTimelineResolver } from "../../Timeline/showTimeline.resolver.js"; import { resolverFindUser } from "../../User/findUser.resolver.js"; import { resolverGetUser } from "../../User/getUser.resolver.js"; +import { mkCalcMadCountGrowthResolver } from "../../Video/calcMadCountGrowth.resolver.js"; import { mkCountAllMadsResolver } from "../../Video/countAllMads.resolver.js"; import { resolverFindMadBySerial } from "../../Video/findMadBySerial.resolver.js"; import { resolverFindVideo } from "../../Video/findVideo.resolver.js"; @@ -50,6 +51,7 @@ import { resolverWhoami } from "./whoami/resolver.js"; export const resolveQuery = (deps: ResolverDeps) => ({ + calcMadCountGrowth: mkCalcMadCountGrowthResolver(deps), countAllMads: mkCountAllMadsResolver(deps), countAllTags: mkCountAllTagsResolver(deps), fetchBilibili: resolverFetchBilibili(deps), diff --git a/src/resolvers/index.ts b/src/resolvers/index.ts index bef9ebd9..23b87bd7 100644 --- a/src/resolvers/index.ts +++ b/src/resolvers/index.ts @@ -1,5 +1,7 @@ /* eslint sort-keys: 2 */ +import { DateTimeResolver } from "graphql-scalars"; + import { resolverBilibiliMADSource } from "../BilibiliMADSource/BilibiliMADSource.resolver.js"; import { resolverBilibiliMADSourceCreateEvent } from "../BilibiliMADSource/BilibiliMADSourceEvent.resolver.js"; import { resolverBilibiliMADSourceEventConnection } from "../BilibiliMADSource/BilibiliMADSourceEventConnection.resolver.js"; @@ -140,6 +142,7 @@ export const makeResolvers = (deps: ResolverDeps) => BilibiliMADSourceEventConnection: resolverBilibiliMADSourceEventConnection(deps), BilibiliOriginalSource: mkBilibiliOriginalSourceResolver(deps), BilibiliOriginalSourceTag: resolverBilibiliOriginalSourceTag(deps), + DateTime: DateTimeResolver, MadRegisteredTimelineEvent: mkMadRegisteredTimelineEventResolver(deps), Mutation: resolveMutation(deps), Mylist: resolveMylist(deps), diff --git a/src/utils/splitDate.test.ts b/src/utils/splitDate.test.ts new file mode 100644 index 00000000..c316195d --- /dev/null +++ b/src/utils/splitDate.test.ts @@ -0,0 +1,12 @@ +import { describe, expect, test } from "vitest"; + +import { splitDate } from "./splitDate.js"; + +describe("splitDate()", () => { + test.each([ + [new Date(100), new Date(200), 5, [new Date(120), new Date(140), new Date(160), new Date(180), new Date(200)]], + ])("case %#", (start, end, split) => { + const actual = splitDate(start, end, split); + expect(actual).toStrictEqual(actual); + }); +}); diff --git a/src/utils/splitDate.ts b/src/utils/splitDate.ts new file mode 100644 index 00000000..8bc6a55f --- /dev/null +++ b/src/utils/splitDate.ts @@ -0,0 +1,5 @@ +export const splitDate = (start: Date, end: Date, split: number) => { + const span = (end.getTime() - start.getTime()) / split; + const res = [...new Array(split)].map((_, i) => new Date(start.getTime() + span * (i + 1))); + return res; +};