> {
const game = typeof src === 'object' ? src : await this.reversiGamesRepository.findOneByOrFail({ id: src });
- const users = await Promise.all([
- this.userEntityService.pack(game.user1 ?? game.user1Id),
- this.userEntityService.pack(game.user2 ?? game.user2Id),
- ]);
+ const user1 = hint?.packedUser1 ?? await this.userEntityService.pack(game.user1 ?? game.user1Id);
+ const user2 = hint?.packedUser2 ?? await this.userEntityService.pack(game.user2 ?? game.user2Id);
return await awaitAll({
id: game.id,
@@ -94,10 +109,10 @@ export class ReversiGameEntityService {
isEnded: game.isEnded,
user1Id: game.user1Id,
user2Id: game.user2Id,
- user1: users[0],
- user2: users[1],
+ user1,
+ user2,
winnerId: game.winnerId,
- winner: game.winnerId ? users.find(u => u.id === game.winnerId)! : null,
+ winner: game.winnerId ? [user1, user2].find(u => u.id === game.winnerId)! : null,
surrenderedUserId: game.surrenderedUserId,
timeoutUserId: game.timeoutUserId,
black: game.black,
@@ -111,10 +126,21 @@ export class ReversiGameEntityService {
}
@bindThis
- public packLiteMany(
- xs: MiReversiGame[],
+ public async packLiteMany(
+ games: MiReversiGame[],
) {
- return Promise.all(xs.map(x => this.packLite(x)));
+ const _user1s = games.map(({ user1, user1Id }) => user1 ?? user1Id);
+ const _user2s = games.map(({ user2, user2Id }) => user2 ?? user2Id);
+ const _userMap = await this.userEntityService.packMany([..._user1s, ..._user2s])
+ .then(users => new Map(users.map(u => [u.id, u])));
+ return Promise.all(
+ games.map(game => {
+ return this.packLite(game, {
+ packedUser1: _userMap.get(game.user1Id),
+ packedUser2: _userMap.get(game.user2Id),
+ });
+ }),
+ );
}
}
diff --git a/packages/backend/src/core/entities/UserListEntityService.ts b/packages/backend/src/core/entities/UserListEntityService.ts
index 09cab24521..b77249c5cb 100644
--- a/packages/backend/src/core/entities/UserListEntityService.ts
+++ b/packages/backend/src/core/entities/UserListEntityService.ts
@@ -50,11 +50,14 @@ export class UserListEntityService {
public async packMembershipsMany(
memberships: MiUserListMembership[],
) {
+ const _users = memberships.map(({ user, userId }) => user ?? userId);
+ const _userMap = await this.userEntityService.packMany(_users)
+ .then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(memberships.map(async x => ({
id: x.id,
createdAt: this.idService.parse(x.id).date.toISOString(),
userId: x.userId,
- user: await this.userEntityService.pack(x.userId),
+ user: _userMap.get(x.userId) ?? await this.userEntityService.pack(x.userId),
withReplies: x.withReplies,
})));
}
diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts
index a620d7c94b..41e5bfe9e4 100644
--- a/packages/backend/src/misc/json-schema.ts
+++ b/packages/backend/src/misc/json-schema.ts
@@ -228,7 +228,7 @@ export type SchemaTypeDef =
p['items']['allOf'] extends ReadonlyArray ? UnionToIntersection>>[] :
never
) :
- p['items'] extends NonNullable ? SchemaTypeDef[] :
+ p['items'] extends NonNullable ? SchemaType[] :
any[]
) :
p['anyOf'] extends ReadonlyArray ? UnionSchemaType & PartialIntersection> :
diff --git a/packages/backend/src/models/Antenna.ts b/packages/backend/src/models/Antenna.ts
index f5e819059e..33e6f48189 100644
--- a/packages/backend/src/models/Antenna.ts
+++ b/packages/backend/src/models/Antenna.ts
@@ -90,9 +90,6 @@ export class MiAntenna {
})
public expression: string | null;
- @Column('boolean')
- public notify: boolean;
-
@Index()
@Column('boolean', {
default: true,
diff --git a/packages/backend/src/models/Instance.ts b/packages/backend/src/models/Instance.ts
index 9863c9d75d..17cd5c6665 100644
--- a/packages/backend/src/models/Instance.ts
+++ b/packages/backend/src/models/Instance.ts
@@ -81,13 +81,22 @@ export class MiInstance {
public isNotResponding: boolean;
/**
- * このインスタンスへの配信を停止するか
+ * このインスタンスと不通になった日時
+ */
+ @Column('timestamp with time zone', {
+ nullable: true,
+ })
+ public notRespondingSince: Date | null;
+
+ /**
+ * このインスタンスへの配信状態
*/
@Index()
- @Column('boolean', {
- default: false,
+ @Column('enum', {
+ default: 'none',
+ enum: ['none', 'manuallySuspended', 'goneSuspended', 'autoSuspendedForNotResponding'],
})
- public isSuspended: boolean;
+ public suspensionState: 'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding';
@Column('varchar', {
length: 64, nullable: true,
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index 04a34bbbb4..ad306fcad6 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -376,6 +376,12 @@ export class MiMeta {
})
public privacyPolicyUrl: string | null;
+ @Column('varchar', {
+ length: 1024,
+ nullable: true,
+ })
+ public inquiryUrl: string | null;
+
@Column('varchar', {
length: 8192,
nullable: true,
diff --git a/packages/backend/src/models/Poll.ts b/packages/backend/src/models/Poll.ts
index c2693dbb19..ca985c8b24 100644
--- a/packages/backend/src/models/Poll.ts
+++ b/packages/backend/src/models/Poll.ts
@@ -8,6 +8,7 @@ import { noteVisibilities } from '@/types.js';
import { id } from './util/id.js';
import { MiNote } from './Note.js';
import type { MiUser } from './User.js';
+import type { MiChannel } from "@/models/Channel.js";
@Entity('poll')
export class MiPoll {
@@ -58,6 +59,14 @@ export class MiPoll {
comment: '[Denormalized]',
})
public userHost: string | null;
+
+ @Index()
+ @Column({
+ ...id(),
+ nullable: true,
+ comment: '[Denormalized]',
+ })
+ public channelId: MiChannel['id'] | null;
//#endregion
constructor(data: Partial) {
diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts
index bd447570dd..d3062d6b36 100644
--- a/packages/backend/src/models/RepositoryModule.ts
+++ b/packages/backend/src/models/RepositoryModule.ts
@@ -5,409 +5,409 @@
import { Module } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
-import { MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame } from './_.js';
+import { MiRepository, MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame, miRepository } from './_.js';
import type { DataSource } from 'typeorm';
import type { Provider } from '@nestjs/common';
const $usersRepository: Provider = {
provide: DI.usersRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUser),
+ useFactory: (db: DataSource) => db.getRepository(MiUser).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $notesRepository: Provider = {
provide: DI.notesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNote),
+ useFactory: (db: DataSource) => db.getRepository(MiNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $announcementsRepository: Provider = {
provide: DI.announcementsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAnnouncement),
+ useFactory: (db: DataSource) => db.getRepository(MiAnnouncement).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $announcementReadsRepository: Provider = {
provide: DI.announcementReadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead),
+ useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $appsRepository: Provider = {
provide: DI.appsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiApp),
+ useFactory: (db: DataSource) => db.getRepository(MiApp).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $avatarDecorationsRepository: Provider = {
provide: DI.avatarDecorationsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration),
+ useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteFavoritesRepository: Provider = {
provide: DI.noteFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteThreadMutingsRepository: Provider = {
provide: DI.noteThreadMutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteReactionsRepository: Provider = {
provide: DI.noteReactionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteReaction),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteReaction).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteUnreadsRepository: Provider = {
provide: DI.noteUnreadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteUnread),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteUnread).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pollsRepository: Provider = {
provide: DI.pollsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPoll),
+ useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pollVotesRepository: Provider = {
provide: DI.pollVotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPollVote),
+ useFactory: (db: DataSource) => db.getRepository(MiPollVote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userProfilesRepository: Provider = {
provide: DI.userProfilesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserProfile),
+ useFactory: (db: DataSource) => db.getRepository(MiUserProfile).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userKeypairsRepository: Provider = {
provide: DI.userKeypairsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserKeypair),
+ useFactory: (db: DataSource) => db.getRepository(MiUserKeypair).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userPendingsRepository: Provider = {
provide: DI.userPendingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserPending),
+ useFactory: (db: DataSource) => db.getRepository(MiUserPending).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userSecurityKeysRepository: Provider = {
provide: DI.userSecurityKeysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey),
+ useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userPublickeysRepository: Provider = {
provide: DI.userPublickeysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserPublickey),
+ useFactory: (db: DataSource) => db.getRepository(MiUserPublickey).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListsRepository: Provider = {
provide: DI.userListsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserList),
+ useFactory: (db: DataSource) => db.getRepository(MiUserList).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListFavoritesRepository: Provider = {
provide: DI.userListFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListMembershipsRepository: Provider = {
provide: DI.userListMembershipsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserListMembership),
+ useFactory: (db: DataSource) => db.getRepository(MiUserListMembership).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userNotePiningsRepository: Provider = {
provide: DI.userNotePiningsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserNotePining),
+ useFactory: (db: DataSource) => db.getRepository(MiUserNotePining).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userIpsRepository: Provider = {
provide: DI.userIpsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserIp),
+ useFactory: (db: DataSource) => db.getRepository(MiUserIp).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $usedUsernamesRepository: Provider = {
provide: DI.usedUsernamesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUsedUsername),
+ useFactory: (db: DataSource) => db.getRepository(MiUsedUsername).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $followingsRepository: Provider = {
provide: DI.followingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFollowing),
+ useFactory: (db: DataSource) => db.getRepository(MiFollowing).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $followRequestsRepository: Provider = {
provide: DI.followRequestsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFollowRequest),
+ useFactory: (db: DataSource) => db.getRepository(MiFollowRequest).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $instancesRepository: Provider = {
provide: DI.instancesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiInstance),
+ useFactory: (db: DataSource) => db.getRepository(MiInstance).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $emojisRepository: Provider = {
provide: DI.emojisRepository,
- useFactory: (db: DataSource) => db.getRepository(MiEmoji),
+ useFactory: (db: DataSource) => db.getRepository(MiEmoji).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $driveFilesRepository: Provider = {
provide: DI.driveFilesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiDriveFile),
+ useFactory: (db: DataSource) => db.getRepository(MiDriveFile).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $driveFoldersRepository: Provider = {
provide: DI.driveFoldersRepository,
- useFactory: (db: DataSource) => db.getRepository(MiDriveFolder),
+ useFactory: (db: DataSource) => db.getRepository(MiDriveFolder).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $metasRepository: Provider = {
provide: DI.metasRepository,
- useFactory: (db: DataSource) => db.getRepository(MiMeta),
+ useFactory: (db: DataSource) => db.getRepository(MiMeta).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $mutingsRepository: Provider = {
provide: DI.mutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $renoteMutingsRepository: Provider = {
provide: DI.renoteMutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $blockingsRepository: Provider = {
provide: DI.blockingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiBlocking),
+ useFactory: (db: DataSource) => db.getRepository(MiBlocking).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $swSubscriptionsRepository: Provider = {
provide: DI.swSubscriptionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiSwSubscription),
+ useFactory: (db: DataSource) => db.getRepository(MiSwSubscription).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $hashtagsRepository: Provider = {
provide: DI.hashtagsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiHashtag),
+ useFactory: (db: DataSource) => db.getRepository(MiHashtag).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $abuseUserReportsRepository: Provider = {
provide: DI.abuseUserReportsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport),
+ useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $registrationTicketsRepository: Provider = {
provide: DI.registrationTicketsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket),
+ useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $authSessionsRepository: Provider = {
provide: DI.authSessionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAuthSession),
+ useFactory: (db: DataSource) => db.getRepository(MiAuthSession).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $accessTokensRepository: Provider = {
provide: DI.accessTokensRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAccessToken),
+ useFactory: (db: DataSource) => db.getRepository(MiAccessToken).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $signinsRepository: Provider = {
provide: DI.signinsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiSignin),
+ useFactory: (db: DataSource) => db.getRepository(MiSignin).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pagesRepository: Provider = {
provide: DI.pagesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPage),
+ useFactory: (db: DataSource) => db.getRepository(MiPage).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pageLikesRepository: Provider = {
provide: DI.pageLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPageLike),
+ useFactory: (db: DataSource) => db.getRepository(MiPageLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $galleryPostsRepository: Provider = {
provide: DI.galleryPostsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiGalleryPost),
+ useFactory: (db: DataSource) => db.getRepository(MiGalleryPost).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $galleryLikesRepository: Provider = {
provide: DI.galleryLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiGalleryLike),
+ useFactory: (db: DataSource) => db.getRepository(MiGalleryLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $moderationLogsRepository: Provider = {
provide: DI.moderationLogsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiModerationLog),
+ useFactory: (db: DataSource) => db.getRepository(MiModerationLog).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipsRepository: Provider = {
provide: DI.clipsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClip),
+ useFactory: (db: DataSource) => db.getRepository(MiClip).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipNotesRepository: Provider = {
provide: DI.clipNotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClipNote),
+ useFactory: (db: DataSource) => db.getRepository(MiClipNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipFavoritesRepository: Provider = {
provide: DI.clipFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClipFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiClipFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $antennasRepository: Provider = {
provide: DI.antennasRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAntenna),
+ useFactory: (db: DataSource) => db.getRepository(MiAntenna).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $promoNotesRepository: Provider = {
provide: DI.promoNotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPromoNote),
+ useFactory: (db: DataSource) => db.getRepository(MiPromoNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $promoReadsRepository: Provider = {
provide: DI.promoReadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPromoRead),
+ useFactory: (db: DataSource) => db.getRepository(MiPromoRead).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $relaysRepository: Provider = {
provide: DI.relaysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRelay),
+ useFactory: (db: DataSource) => db.getRepository(MiRelay).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelsRepository: Provider = {
provide: DI.channelsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannel),
+ useFactory: (db: DataSource) => db.getRepository(MiChannel).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelFollowingsRepository: Provider = {
provide: DI.channelFollowingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing),
+ useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelFavoritesRepository: Provider = {
provide: DI.channelFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $registryItemsRepository: Provider = {
provide: DI.registryItemsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRegistryItem),
+ useFactory: (db: DataSource) => db.getRepository(MiRegistryItem).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $webhooksRepository: Provider = {
provide: DI.webhooksRepository,
- useFactory: (db: DataSource) => db.getRepository(MiWebhook),
+ useFactory: (db: DataSource) => db.getRepository(MiWebhook).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $adsRepository: Provider = {
provide: DI.adsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAd),
+ useFactory: (db: DataSource) => db.getRepository(MiAd).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $passwordResetRequestsRepository: Provider = {
provide: DI.passwordResetRequestsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest),
+ useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $retentionAggregationsRepository: Provider = {
provide: DI.retentionAggregationsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation),
+ useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $flashsRepository: Provider = {
provide: DI.flashsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFlash),
+ useFactory: (db: DataSource) => db.getRepository(MiFlash).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $flashLikesRepository: Provider = {
provide: DI.flashLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFlashLike),
+ useFactory: (db: DataSource) => db.getRepository(MiFlashLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $rolesRepository: Provider = {
provide: DI.rolesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRole),
+ useFactory: (db: DataSource) => db.getRepository(MiRole).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $roleAssignmentsRepository: Provider = {
provide: DI.roleAssignmentsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment),
+ useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userMemosRepository: Provider = {
provide: DI.userMemosRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserMemo),
+ useFactory: (db: DataSource) => db.getRepository(MiUserMemo).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $bubbleGameRecordsRepository: Provider = {
provide: DI.bubbleGameRecordsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord),
+ useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $reversiGamesRepository: Provider = {
provide: DI.reversiGamesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiReversiGame),
+ useFactory: (db: DataSource) => db.getRepository(MiReversiGame).extend(miRepository as MiRepository),
inject: [DI.db],
};
diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts
index 43d42d80dd..2e6a41586e 100644
--- a/packages/backend/src/models/_.ts
+++ b/packages/backend/src/models/_.ts
@@ -3,6 +3,13 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder, TypeORMError } from 'typeorm';
+import { DriverUtils } from 'typeorm/driver/DriverUtils.js';
+import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
+import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
+import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
+import { ObjectUtils } from 'typeorm/util/ObjectUtils.js';
+import { OrmUtils } from 'typeorm/util/OrmUtils.js';
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import { MiAccessToken } from '@/models/AccessToken.js';
import { MiAd } from '@/models/Ad.js';
@@ -70,8 +77,70 @@ import { MiFlashLike } from '@/models/FlashLike.js';
import { MiUserListFavorite } from '@/models/UserListFavorite.js';
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
import { MiReversiGame } from '@/models/ReversiGame.js';
+import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
-import type { Repository } from 'typeorm';
+export interface MiRepository {
+ createTableColumnNames(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder): string[];
+ createTableColumnNamesWithPrimaryKey(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder): string[];
+ insertOne(this: Repository & MiRepository, entity: QueryDeepPartialEntity, findOptions?: Pick, 'relations'>): Promise;
+ selectAliasColumnNames(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder, builder: SelectQueryBuilder): void;
+}
+
+export const miRepository = {
+ createTableColumnNames(queryBuilder) {
+ // @ts-expect-error -- protected
+ const insertedColumns = queryBuilder.getInsertedColumns();
+ if (insertedColumns.length) {
+ return insertedColumns.map(column => column.databaseName);
+ }
+ if (!queryBuilder.expressionMap.mainAlias?.hasMetadata && !queryBuilder.expressionMap.insertColumns.length) {
+ // @ts-expect-error -- protected
+ const valueSets = queryBuilder.getValueSets();
+ if (valueSets.length === 1) {
+ return Object.keys(valueSets[0]);
+ }
+ }
+ return queryBuilder.expressionMap.insertColumns;
+ },
+ createTableColumnNamesWithPrimaryKey(queryBuilder) {
+ const columnNames = this.createTableColumnNames(queryBuilder);
+ if (!columnNames.includes('id')) {
+ columnNames.unshift('id');
+ }
+ return columnNames;
+ },
+ async insertOne(entity, findOptions?) {
+ const queryBuilder = this.createQueryBuilder().insert().values(entity);
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const mainAlias = queryBuilder.expressionMap.mainAlias!;
+ const name = mainAlias.name;
+ mainAlias.name = 't';
+ const columnNames = this.createTableColumnNamesWithPrimaryKey(queryBuilder);
+ queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
+ const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ builder.expressionMap.mainAlias!.tablePath = 'cte';
+ this.selectAliasColumnNames(queryBuilder, builder);
+ if (findOptions) {
+ builder.setFindOptions(findOptions);
+ }
+ const raw = await builder.execute();
+ mainAlias.name = name;
+ const relationId = await new RelationIdLoader(builder.connection, this.queryRunner, builder.expressionMap.relationIdAttributes).load(raw);
+ const relationCount = await new RelationCountLoader(builder.connection, this.queryRunner, builder.expressionMap.relationCountAttributes).load(raw);
+ const result = new RawSqlResultsToEntityTransformer(builder.expressionMap, builder.connection.driver, relationId, relationCount, this.queryRunner).transform(raw, mainAlias);
+ return result[0];
+ },
+ selectAliasColumnNames(queryBuilder, builder) {
+ let selectOrAddSelect = (selection: string, selectionAliasName?: string) => {
+ selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName);
+ return builder.select(selection, selectionAliasName);
+ };
+ for (const columnName of this.createTableColumnNamesWithPrimaryKey(queryBuilder)) {
+ selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`);
+ }
+ },
+} satisfies MiRepository;
export {
MiAbuseUserReport,
@@ -143,70 +212,70 @@ export {
MiReversiGame,
};
-export type AbuseUserReportsRepository = Repository;
-export type AccessTokensRepository = Repository;
-export type AdsRepository = Repository;
-export type AnnouncementsRepository = Repository;
-export type AnnouncementReadsRepository = Repository;
-export type AntennasRepository = Repository;
-export type AppsRepository = Repository;
-export type AvatarDecorationsRepository = Repository;
-export type AuthSessionsRepository = Repository;
-export type BlockingsRepository = Repository;
-export type ChannelFollowingsRepository = Repository;
-export type ChannelFavoritesRepository = Repository;
-export type ClipsRepository = Repository;
-export type ClipNotesRepository = Repository;
-export type ClipFavoritesRepository = Repository;
-export type DriveFilesRepository = Repository;
-export type DriveFoldersRepository = Repository;
-export type EmojisRepository = Repository;
-export type FollowingsRepository = Repository;
-export type FollowRequestsRepository = Repository;
-export type GalleryLikesRepository = Repository;
-export type GalleryPostsRepository = Repository;
-export type HashtagsRepository = Repository;
-export type InstancesRepository = Repository;
-export type MetasRepository = Repository;
-export type ModerationLogsRepository = Repository;
-export type MutingsRepository = Repository;
-export type RenoteMutingsRepository = Repository;
-export type NotesRepository = Repository;
-export type NoteFavoritesRepository = Repository;
-export type NoteReactionsRepository = Repository;
-export type NoteThreadMutingsRepository = Repository;
-export type NoteUnreadsRepository = Repository;
-export type PagesRepository = Repository;
-export type PageLikesRepository = Repository;
-export type PasswordResetRequestsRepository = Repository;
-export type PollsRepository = Repository;
-export type PollVotesRepository = Repository;
-export type PromoNotesRepository = Repository;
-export type PromoReadsRepository = Repository;
-export type RegistrationTicketsRepository = Repository;
-export type RegistryItemsRepository = Repository;
-export type RelaysRepository = Repository;
-export type SigninsRepository = Repository;
-export type SwSubscriptionsRepository = Repository;
-export type UsedUsernamesRepository = Repository;
-export type UsersRepository = Repository;
-export type UserIpsRepository = Repository;
-export type UserKeypairsRepository = Repository;
-export type UserListsRepository = Repository;
-export type UserListFavoritesRepository = Repository;
-export type UserListMembershipsRepository = Repository;
-export type UserNotePiningsRepository = Repository;
-export type UserPendingsRepository = Repository;
-export type UserProfilesRepository = Repository;
-export type UserPublickeysRepository = Repository;
-export type UserSecurityKeysRepository = Repository;
-export type WebhooksRepository = Repository;
-export type ChannelsRepository = Repository;
-export type RetentionAggregationsRepository = Repository;
-export type RolesRepository = Repository;
-export type RoleAssignmentsRepository = Repository;
-export type FlashsRepository = Repository;
-export type FlashLikesRepository = Repository;
-export type UserMemoRepository = Repository;
-export type BubbleGameRecordsRepository = Repository;
-export type ReversiGamesRepository = Repository;
+export type AbuseUserReportsRepository = Repository & MiRepository;
+export type AccessTokensRepository = Repository & MiRepository;
+export type AdsRepository = Repository & MiRepository;
+export type AnnouncementsRepository = Repository & MiRepository