From 6bb048e991f73189f29c726fac337adbb4911dc6 Mon Sep 17 00:00:00 2001 From: Tatsuto YAMAMOTO Date: Mon, 7 Aug 2023 23:31:10 +0900 Subject: [PATCH 1/2] wip --- src/repository/prisma/user.ts | 36 ++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/repository/prisma/user.ts b/src/repository/prisma/user.ts index b824b83..48b62e3 100644 --- a/src/repository/prisma/user.ts +++ b/src/repository/prisma/user.ts @@ -4,6 +4,7 @@ import { User, UserAPData, UserFollowEvent } from "../../domain/user.js"; import { Snowflake } from "../../helpers/id_generator.js"; import { PrismaClient } from "@prisma/client"; import { PrismaErrorConverter } from "./error.js"; +import { InternalError } from "../../helpers/errors.js"; export class UserRepository implements IUserRepository { private prisma: PrismaClient; @@ -136,8 +137,15 @@ export class UserRepository implements IUserRepository { } } + private isUser(obj: any): obj is user { + return typeof obj.id === "string"; + } + private convertToDomain(ew: Array): Array { - return ew.map((e) => { + return ew.map((e: any) => { + if (!this.isUser(e)) { + throw new InternalError(); + } return new User({ id: e.id as Snowflake, bio: e.bio, @@ -228,3 +236,29 @@ export class UserRepository implements IUserRepository { }); } } + +type user = { + id: string; + serverId: string; + bio: string; + createdAt: Date; + handle: string; + fullHandle: string; + headerImageURL: string; + iconImageURL: string; + nickName: string; + isLocalUser: boolean; + password: string; + role: number; + following: object[]; + userAPData: { + followersURL: string; + followingURL: string; + inboxURL: string; + outboxURL: string; + privateKey: string | null; + publicKey: string; + id: string; + userID: string; + }; +}; From 3f29ac5d53715807534af84781a15e2a8c4e00a9 Mon Sep 17 00:00:00 2001 From: Tatsuto YAMAMOTO Date: Tue, 8 Aug 2023 22:53:37 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=E3=82=AA=E3=83=96=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=82=AF=E3=83=88=E5=A4=89=E6=8F=9B=E3=81=A7=E5=9E=8B?= =?UTF-8?q?=E3=82=92=E4=BD=BF=E3=81=86=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/repository/prisma/media.ts | 44 +++++++--- src/repository/prisma/post.ts | 134 ++++++++++++++++-------------- src/repository/prisma/reaction.ts | 21 ++--- src/repository/prisma/server.ts | 32 +++++-- src/repository/prisma/user.ts | 99 ++++++++++------------ 5 files changed, 181 insertions(+), 149 deletions(-) diff --git a/src/repository/prisma/media.ts b/src/repository/prisma/media.ts index 0e8d4b2..7b43084 100644 --- a/src/repository/prisma/media.ts +++ b/src/repository/prisma/media.ts @@ -3,6 +3,7 @@ import { Media } from "../../domain/media.js"; import { Failure, Result, Success } from "../../helpers/result.js"; import { Snowflake } from "../../helpers/id_generator.js"; import { PrismaClient } from "@prisma/client"; +import { PrismaErrorConverter } from "./error.js"; export class MediaRepository implements IMediaRepository { private prisma: PrismaClient; @@ -31,7 +32,7 @@ export class MediaRepository implements IMediaRepository { }); return new Success(this.convertToDomain(res)); } catch (e: unknown) { - return new Failure(new Error("failed to create media", e as any)); + return new Failure(PrismaErrorConverter(e)); } } @@ -42,9 +43,9 @@ export class MediaRepository implements IMediaRepository { id: id, }, }); - return new Success(this.convertToDomain(res)); + return new Success(this.convertToDomain(res as MediaEntity)); } catch (e: unknown) { - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } @@ -55,9 +56,11 @@ export class MediaRepository implements IMediaRepository { postID: id, }, }); - return new Success(res.map((v: any) => this.convertToDomain(v))); + return new Success( + (res as MediaEntity[]).map((v) => this.convertToDomain(v)), + ); } catch (e: unknown) { - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } @@ -68,21 +71,23 @@ export class MediaRepository implements IMediaRepository { authorID: id, }, }); - return new Success(res.map((v: any) => this.convertToDomain(v))); + return new Success( + (res as MediaEntity[]).map((v) => this.convertToDomain(v)), + ); } catch (e: unknown) { - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } - async Update(m: Media): Promise> { + async Update(): Promise> { return new Failure(new Error("")); } - private convertToDomain(v: any): Media { + private convertToDomain(v: MediaEntity): Media { return new Media({ - id: v.id, - authorID: v.authorID, - postID: v.postID, + id: v.id as Snowflake, + authorID: v.authorID as Snowflake, + postID: v.postID as Snowflake, blurhash: v.blurhash, cached: v.cached, isSensitive: v.isSensitive, @@ -95,3 +100,18 @@ export class MediaRepository implements IMediaRepository { }); } } + +export type MediaEntity = { + id: string; + authorID: string; + postID: string; + blurhash: string; + cached: boolean; + isSensitive: boolean; + md5Sum: string; + name: string; + size: number; + thumbnailURL: string; + type: string; + url: string; +}; diff --git a/src/repository/prisma/post.ts b/src/repository/prisma/post.ts index bd006a5..ea7079b 100644 --- a/src/repository/prisma/post.ts +++ b/src/repository/prisma/post.ts @@ -5,6 +5,9 @@ import { Snowflake } from "../../helpers/id_generator.js"; import { Media } from "../../domain/media.js"; import { PrismaClient } from "@prisma/client"; import { User, UserAPData, UserFollowEvent } from "../../domain/user.js"; +import { MediaEntity } from "./media.js"; +import { PrismaErrorConverter } from "./error.js"; +import { PostReactionEntity } from "./reaction.js"; export class PostRepository implements IPostRepository { private prisma: PrismaClient; @@ -37,10 +40,10 @@ export class PostRepository implements IPostRepository { attachments: true, }, }); - return new Success(this.convertToDomain(res)); + return new Success(this.convertToDomain(res as PostEntity)); } catch (e: unknown) { console.log(e); - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } @@ -56,7 +59,7 @@ export class PostRepository implements IPostRepository { }); return new Success(void ""); } catch (e: unknown) { - return new Failure(new Error("failed to delete post", e as Error as any)); + return new Failure(PrismaErrorConverter(e)); } } @@ -75,7 +78,7 @@ export class PostRepository implements IPostRepository { return new Success(res.map((r) => this.convertToDomain(r))); } catch (e: unknown) { - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } @@ -92,20 +95,19 @@ export class PostRepository implements IPostRepository { }, }); - return new Success(this.convertToDomain(res)); + return new Success(this.convertToDomain(res as PostEntity)); } catch (e: unknown) { - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } - async Update(p: Post): Promise> { + async Update(): Promise> { return new Failure(new Error("")); } // 時系列順にフォローしているユーザーと自分自身の投稿を取得 async ChronologicalPosts( userID: Snowflake, - cursor: number, ): AsyncResult<{ posts: Post; author: User }[], Error> { try { const posts = await this.prisma.post.findMany({ @@ -145,35 +147,31 @@ export class PostRepository implements IPostRepository { posts.map((p) => { return { posts: new Post({ - attachments: !p.attachments - ? new Array() - : p.attachments.map((v: any) => { - return new Media({ - authorID: v.authorID, - blurhash: v.blurhash, - cached: v.cached, - id: v.id, - isSensitive: v.isSensitive, - md5Sum: v.md5Sum, - name: v.name, - postID: v.postID, - size: v.size, - thumbnailURL: v.thumbnailURL, - type: v.type, - url: v.url, - }); - }), + attachments: p.attachments?.map((v: MediaEntity) => { + return new Media({ + id: v.id as Snowflake, + authorID: v.authorID as Snowflake, + postID: v.postID as Snowflake, + blurhash: v.blurhash, + cached: v.cached, + isSensitive: v.isSensitive, + md5Sum: v.md5Sum, + name: v.name, + size: v.size, + thumbnailURL: v.thumbnailURL, + type: v.type, + url: v.url, + }); + }), authorID: p.authorID as Snowflake, createdAt: p.createdAt, id: p.id as Snowflake, - reactions: !p.reactions - ? new Array() - : p.reactions.map((v: any) => { - return new PostReactionEvent( - v.postId as Snowflake, - v.userId as Snowflake, - ); - }), + reactions: p.reactions?.map((v: PostReactionEntity) => { + return new PostReactionEvent( + v.postId as Snowflake, + v.userId as Snowflake, + ); + }), text: p.text, visibility: 0, }), @@ -206,44 +204,42 @@ export class PostRepository implements IPostRepository { }), ); } catch (e: unknown) { - return new Failure(new Error(e as Error as any)); + return new Failure(PrismaErrorConverter(e)); } } - private convertToDomain(i: any): Post { + private convertToDomain(i: PostEntity): Post { try { return new Post({ id: i.id as Snowflake, - authorID: i.authorID, + authorID: i.authorID as Snowflake, createdAt: i.createdAt, text: i.text, visibility: i.visibility, - reactions: !i.reactions - ? new Array() - : i.reactions.map((v: any) => { - return new PostReactionEvent( - v.postId as Snowflake, - v.userId as Snowflake, - ); - }), - attachments: !i.attachments - ? new Array() - : i.attachments.map((v: any) => { - return new Media({ - authorID: v.authorID, - blurhash: v.blurhash, - cached: v.cached, - id: v.id, - isSensitive: v.isSensitive, - md5Sum: v.md5Sum, - name: v.name, - postID: v.postID, - size: v.size, - thumbnailURL: v.thumbnailURL, - type: v.type, - url: v.url, - }); - }), + reactions: + i.reactions?.map((v: PostReactionEntity): PostReactionEvent => { + return new PostReactionEvent( + v.postId as Snowflake, + v.userId as Snowflake, + ); + }) ?? new Array(), + attachments: + i.attachments?.map((v) => { + return new Media({ + id: v.id as Snowflake, + authorID: v.authorID as Snowflake, + postID: v.postID as Snowflake, + blurhash: v.blurhash, + cached: v.cached, + isSensitive: v.isSensitive, + md5Sum: v.md5Sum, + name: v.name, + size: v.size, + thumbnailURL: v.thumbnailURL, + type: v.type, + url: v.url, + }); + }) ?? new Array(), }); } catch (e: unknown) { console.log(i.reactions, i.attachments); @@ -251,3 +247,15 @@ export class PostRepository implements IPostRepository { } } } + +type PostEntity = { + id: string; + authorID: string; + createdAt: Date; + text: string; + visibility: number; + reactions?: PostReactionEntity[]; + attachments?: AttachmentEntity[]; +}; + +type AttachmentEntity = MediaEntity; diff --git a/src/repository/prisma/reaction.ts b/src/repository/prisma/reaction.ts index 1680e61..016871c 100644 --- a/src/repository/prisma/reaction.ts +++ b/src/repository/prisma/reaction.ts @@ -3,6 +3,7 @@ import { PrismaClient } from "@prisma/client"; import { PostReactionEvent } from "../../domain/post.js"; import { AsyncResult, Failure, Success } from "../../helpers/result.js"; import { Snowflake } from "../../helpers/id_generator.js"; +import { PrismaErrorConverter } from "./error.js"; export class ReactionRepository implements IReactionRepository { private readonly prisma: PrismaClient; @@ -28,11 +29,9 @@ export class ReactionRepository implements IReactionRepository { }, }); - return new Success(this.toDomain([res])); + return new Success(this.toDomain(res as PostReactionEntity)); } catch (e: unknown) { - return new Failure( - new Error("failed to create reaction", e as Error as any), - ); + return new Failure(PrismaErrorConverter(e)); } } @@ -50,11 +49,9 @@ export class ReactionRepository implements IReactionRepository { }, }); - return new Success(this.toDomain(res)); + return new Success(this.toDomain(res as PostReactionEntity)); } catch (e: unknown) { - return new Failure( - new Error("failed to find reaction", e as Error as any), - ); + return new Failure(PrismaErrorConverter(e)); } } @@ -70,13 +67,13 @@ export class ReactionRepository implements IReactionRepository { }); return new Success(void ""); } catch (e: unknown) { - return new Failure( - new Error("failed to undo reaction", e as Error as any), - ); + return new Failure(PrismaErrorConverter(e)); } } - private toDomain(v: any) { + private toDomain(v: PostReactionEntity) { return new PostReactionEvent(v.postId as Snowflake, v.userId as Snowflake); } } + +export type PostReactionEntity = { postId: string; userId: string }; diff --git a/src/repository/prisma/server.ts b/src/repository/prisma/server.ts index 5fa2eca..22ac152 100644 --- a/src/repository/prisma/server.ts +++ b/src/repository/prisma/server.ts @@ -3,11 +3,12 @@ import { Server } from "../../domain/server.js"; import { Failure, Result, Success } from "../../helpers/result.js"; import { Snowflake } from "../../helpers/id_generator.js"; import { PrismaClient } from "@prisma/client"; +import { PrismaErrorConverter } from "./error.js"; export class ServerRepository implements IServerRepository { private prisma: PrismaClient; - constructor(prisma: any) { + constructor(prisma: PrismaClient) { this.prisma = prisma; } @@ -28,9 +29,9 @@ export class ServerRepository implements IServerRepository { }, }); - return new Success(this.convertToDomain(res)); + return new Success(this.convertToDomain(res as ServerEntity)); } catch (e: unknown) { - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } @@ -42,9 +43,9 @@ export class ServerRepository implements IServerRepository { }, }); - return new Success(this.convertToDomain(res)); + return new Success(this.convertToDomain(res as ServerEntity)); } catch (e: unknown) { - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } @@ -56,17 +57,17 @@ export class ServerRepository implements IServerRepository { }, }); - return new Success(this.convertToDomain(res)); + return new Success(this.convertToDomain(res as ServerEntity)); } catch (e: unknown) { - return new Failure(new Error(e as any)); + return new Failure(PrismaErrorConverter(e)); } } - async Update(s: Server): Promise> { + async Update(): Promise> { return new Failure(new Error("")); } - private convertToDomain(i: any): Server { + private convertToDomain(i: ServerEntity): Server { return new Server({ id: i.id as Snowflake, description: i.description, @@ -81,3 +82,16 @@ export class ServerRepository implements IServerRepository { }); } } + +export type ServerEntity = { + id: string; + description: string; + faviconURL: string; + host: string; + iconURL: string; + maintainer: string; + maintainerEmail: string; + name: string; + softwareName: string; + softwareVersion: string; +}; diff --git a/src/repository/prisma/user.ts b/src/repository/prisma/user.ts index 61b013b..15fa15b 100644 --- a/src/repository/prisma/user.ts +++ b/src/repository/prisma/user.ts @@ -4,7 +4,6 @@ import { User, UserAPData, UserFollowEvent } from "../../domain/user.js"; import { Snowflake } from "../../helpers/id_generator.js"; import { PrismaClient } from "@prisma/client"; import { PrismaErrorConverter } from "./error.js"; -import { InternalError } from "../../helpers/errors.js"; export class UserRepository implements IUserRepository { private prisma: PrismaClient; @@ -70,7 +69,10 @@ export class UserRepository implements IUserRepository { follower: { include: { follower: true, following: true } }, }, }); - return new Success(this.convertToDomain([res])[0]); + // Memo: + // follower[N].following -> そのユーザーがフォローしているユーザー + // following[N].follower -> そのユーザーをフォローしているユーザー + return new Success(this.convertToDomain([res as UserEntity])[0]); } catch (e: unknown) { return new Failure(PrismaErrorConverter(e)); } @@ -78,8 +80,7 @@ export class UserRepository implements IUserRepository { async FindByID(id: Snowflake): Promise> { try { - // Fixme: ID検索がFindManyになっている - const res = await this.prisma.user.findMany({ + const res = await this.prisma.user.findUnique({ where: { id: id, }, @@ -89,13 +90,15 @@ export class UserRepository implements IUserRepository { follower: { include: { follower: true, following: true } }, }, }); - return new Success(this.convertToDomain(res)[0]); + + return new Success(this.convertToDomain([res as UserEntity])[0]); + // return new Success(this.convertToDomain([res as UserEntity])[0]); } catch (e: unknown) { return new Failure(PrismaErrorConverter(e)); } } - async Update(u: User): Promise> { + async Update(): Promise> { return new Failure(new Error("")); } @@ -137,15 +140,8 @@ export class UserRepository implements IUserRepository { } } - private isUser(obj: any): obj is user { - return typeof obj.id === "string"; - } - - private convertToDomain(ew: Array): Array { - return ew.map((e: any) => { - if (!this.isUser(e)) { - throw new InternalError(); - } + private convertToDomain(ew: Array): Array { + return ew.map((e) => { return new User({ id: e.id as Snowflake, bio: e.bio, @@ -158,41 +154,24 @@ export class UserRepository implements IUserRepository { nickName: e.nickName, password: e.password, role: e.role, - following: e.following.map( - (v: { - following: { - id: string; - fullHandle: string; - nickName: string; - iconImageURL: string; - bio: string; - }; - follower: { - id: string; - fullHandle: string; - nickName: string; - iconImageURL: string; - bio: string; - }; - }): UserFollowEvent => { - return new UserFollowEvent( - { - id: v.following.id as Snowflake, - bio: v.following.bio, - fullHandle: v.following.fullHandle, - iconImageURL: v.following.iconImageURL, - nickName: v.following.nickName, - }, - { - id: v.follower.id as Snowflake, - bio: v.follower.bio, - fullHandle: v.follower.fullHandle, - iconImageURL: v.follower.iconImageURL, - nickName: v.follower.nickName, - }, - ); - }, - ), + following: e.follower.map((v) => { + return new UserFollowEvent( + { + id: v.following.id as Snowflake, + bio: v.following.bio, + iconImageURL: v.following.iconImageURL, + nickName: v.following.nickName, + fullHandle: v.following.fullHandle, + }, + { + id: v.follower.id as Snowflake, + bio: v.follower.bio, + iconImageURL: v.follower.iconImageURL, + nickName: v.follower.nickName, + fullHandle: v.follower.fullHandle, + }, + ); + }), apData: new UserAPData({ followersURL: e.userAPData.followersURL ?? "", followingURL: e.userAPData.followingURL ?? "", @@ -269,7 +248,7 @@ export class UserRepository implements IUserRepository { } } -type user = { +export type UserEntity = { id: string; serverId: string; bio: string; @@ -282,7 +261,22 @@ type user = { isLocalUser: boolean; password: string; role: number; - following: object[]; + follower: Array<{ + follower: { + id: string; + fullHandle: string; + nickName: string; + bio: string; + iconImageURL: string; + }; + following: { + id: string; + fullHandle: string; + nickName: string; + bio: string; + iconImageURL: string; + }; + }>; userAPData: { followersURL: string; followingURL: string; @@ -291,6 +285,5 @@ type user = { privateKey: string | null; publicKey: string; id: string; - userID: string; }; };