fix(backend): use insertOne insteadof insert/findOneOrFail combination (#13908)

* fix(backend): use insertOne insteadof insert/findOneOrFail combination

* fix: typo

* fix(backend): inherit mainAlias?

* refactor(backend): use extend

* fix(backend): invalid entityTarget

* fix(backend): fake where

* chore: debug

* chore: debug

* test: log

* fix(backend): column names

* fix(backend): remove dummy from

* revert: log

* fix(backend): position

* fix(backend): automatic aliasing

* chore(backend): alias

* chore(backend): remove from

* fix(backend): type

* fix(backend): avoid pure name

* test(backend): fix type

* chore(backend): use cte

* fix(backend): avoid useless alias

* fix(backend): fix typo

* fix(backend): __disambiguation__

* fix(backend): quote

* chore(backend): t

* chore(backend): accessible

* chore(backend): concrete returning

* fix(backend): quote

* chore: log more

* chore: log metadata

* chore(backend): use raw

* fix(backend): returning column name

* fix(backend): transform

* build(backend): wanna logging

* build(backend): transform empty

* build(backend): build alias

* build(backend): restore name

* chore: return entity

* fix: test case

* test(backend): 204

* chore(backend): log sql

* chore(backend): assert user joined

* fix(backend): typo

* chore(backend): log long sql

* chore(backend): log join

* chore(backend): log join depth null

* chore(backend): joinAttributes

* chore(backend): override createJoinExpression

* chore: join log

* fix(backend): escape

* test(backend): log log

* chore(backend): join gonna success?

* chore(backend): relations

* chore(backend): undefined

* chore(backend): target

* chore(backend): remove log

* chore(backend): log chart update

* chore(backend): log columns

* chore(backend): check hasMetadata

* chore(backend): unshift id when not included

* chore(backend): missing select

* chore(backend): remove debug code
This commit is contained in:
Acid Chicken 2024-06-01 11:16:44 +09:00 committed by GitHub
parent ecf7945fe8
commit 2b8056a852
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 319 additions and 215 deletions

View File

@ -67,7 +67,7 @@ export class AnnouncementService {
@bindThis @bindThis
public async create(values: Partial<MiAnnouncement>, moderator?: MiUser): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> { public async create(values: Partial<MiAnnouncement>, moderator?: MiUser): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> {
const announcement = await this.announcementsRepository.insert({ const announcement = await this.announcementsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
updatedAt: null, updatedAt: null,
title: values.title, title: values.title,
@ -79,7 +79,7 @@ export class AnnouncementService {
silence: values.silence, silence: values.silence,
needConfirmationToRead: values.needConfirmationToRead, needConfirmationToRead: values.needConfirmationToRead,
userId: values.userId, userId: values.userId,
}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0])); });
const packed = await this.announcementEntityService.pack(announcement); const packed = await this.announcementEntityService.pack(announcement);

View File

@ -55,10 +55,10 @@ export class AvatarDecorationService implements OnApplicationShutdown {
@bindThis @bindThis
public async create(options: Partial<MiAvatarDecoration>, moderator?: MiUser): Promise<MiAvatarDecoration> { public async create(options: Partial<MiAvatarDecoration>, moderator?: MiUser): Promise<MiAvatarDecoration> {
const created = await this.avatarDecorationsRepository.insert({ const created = await this.avatarDecorationsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
...options, ...options,
}).then(x => this.avatarDecorationsRepository.findOneByOrFail(x.identifiers[0])); });
this.globalEventService.publishInternalEvent('avatarDecorationCreated', created); this.globalEventService.publishInternalEvent('avatarDecorationCreated', created);

View File

@ -45,13 +45,13 @@ export class ClipService {
throw new ClipService.TooManyClipsError(); throw new ClipService.TooManyClipsError();
} }
const clip = await this.clipsRepository.insert({ const clip = await this.clipsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: me.id, userId: me.id,
name: name, name: name,
isPublic: isPublic, isPublic: isPublic,
description: description, description: description,
}).then(x => this.clipsRepository.findOneByOrFail(x.identifiers[0])); });
return clip; return clip;
} }

View File

@ -68,7 +68,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
localOnly: boolean; localOnly: boolean;
roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][]; roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][];
}, moderator?: MiUser): Promise<MiEmoji> { }, moderator?: MiUser): Promise<MiEmoji> {
const emoji = await this.emojisRepository.insert({ const emoji = await this.emojisRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
updatedAt: new Date(), updatedAt: new Date(),
name: data.name, name: data.name,
@ -82,7 +82,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
isSensitive: data.isSensitive, isSensitive: data.isSensitive,
localOnly: data.localOnly, localOnly: data.localOnly,
roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction, roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction,
}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0])); });
if (data.host == null) { if (data.host == null) {
this.localEmojisCache.refresh(); this.localEmojisCache.refresh();

View File

@ -220,7 +220,7 @@ export class DriveService {
file.size = size; file.size = size;
file.storedInternal = false; file.storedInternal = false;
return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0])); return await this.driveFilesRepository.insertOne(file);
} else { // use internal storage } else { // use internal storage
const accessKey = randomUUID(); const accessKey = randomUUID();
const thumbnailAccessKey = 'thumbnail-' + randomUUID(); const thumbnailAccessKey = 'thumbnail-' + randomUUID();
@ -254,7 +254,7 @@ export class DriveService {
file.md5 = hash; file.md5 = hash;
file.size = size; file.size = size;
return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0])); return await this.driveFilesRepository.insertOne(file);
} }
} }
@ -615,7 +615,7 @@ export class DriveService {
file.type = info.type.mime; file.type = info.type.mime;
file.storedInternal = false; file.storedInternal = false;
file = await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0])); file = await this.driveFilesRepository.insertOne(file);
} catch (err) { } catch (err) {
// duplicate key error (when already registered) // duplicate key error (when already registered)
if (isDuplicateKeyValueError(err)) { if (isDuplicateKeyValueError(err)) {

View File

@ -55,11 +55,11 @@ export class FederatedInstanceService implements OnApplicationShutdown {
const index = await this.instancesRepository.findOneBy({ host }); const index = await this.instancesRepository.findOneBy({ host });
if (index == null) { if (index == null) {
const i = await this.instancesRepository.insert({ const i = await this.instancesRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
host, host,
firstRetrievedAt: new Date(), firstRetrievedAt: new Date(),
}).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0])); });
this.federatedInstanceCache.set(host, i); this.federatedInstanceCache.set(host, i);
return i; return i;

View File

@ -53,11 +53,11 @@ export class RelayService {
@bindThis @bindThis
public async addRelay(inbox: string): Promise<MiRelay> { public async addRelay(inbox: string): Promise<MiRelay> {
const relay = await this.relaysRepository.insert({ const relay = await this.relaysRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
inbox, inbox,
status: 'requesting', status: 'requesting',
}).then(x => this.relaysRepository.findOneByOrFail(x.identifiers[0])); });
const relayActor = await this.getRelayActor(); const relayActor = await this.getRelayActor();
const follow = await this.apRendererService.renderFollowRelay(relay, relayActor); const follow = await this.apRendererService.renderFollowRelay(relay, relayActor);

View File

@ -281,7 +281,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
@bindThis @bindThis
private async matched(parentId: MiUser['id'], childId: MiUser['id'], options: { noIrregularRules: boolean; }): Promise<MiReversiGame> { private async matched(parentId: MiUser['id'], childId: MiUser['id'], options: { noIrregularRules: boolean; }): Promise<MiReversiGame> {
const game = await this.reversiGamesRepository.insert({ const game = await this.reversiGamesRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
user1Id: parentId, user1Id: parentId,
user2Id: childId, user2Id: childId,
@ -294,10 +294,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
bw: 'random', bw: 'random',
isLlotheo: false, isLlotheo: false,
noIrregularRules: options.noIrregularRules, noIrregularRules: options.noIrregularRules,
}).then(x => this.reversiGamesRepository.findOneOrFail({ }, { relations: ['user1', 'user2'] });
where: { id: x.identifiers[0].id },
relations: ['user1', 'user2'],
}));
this.cacheGame(game); this.cacheGame(game);
const packed = await this.reversiGameEntityService.packDetail(game); const packed = await this.reversiGameEntityService.packDetail(game);

View File

@ -471,12 +471,12 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
} }
} }
const created = await this.roleAssignmentsRepository.insert({ const created = await this.roleAssignmentsRepository.insertOne({
id: this.idService.gen(now), id: this.idService.gen(now),
expiresAt: expiresAt, expiresAt: expiresAt,
roleId: roleId, roleId: roleId,
userId: userId, userId: userId,
}).then(x => this.roleAssignmentsRepository.findOneByOrFail(x.identifiers[0])); });
this.rolesRepository.update(roleId, { this.rolesRepository.update(roleId, {
lastUsedAt: new Date(), lastUsedAt: new Date(),
@ -558,7 +558,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
@bindThis @bindThis
public async create(values: Partial<MiRole>, moderator?: MiUser): Promise<MiRole> { public async create(values: Partial<MiRole>, moderator?: MiUser): Promise<MiRole> {
const date = new Date(); const date = new Date();
const created = await this.rolesRepository.insert({ const created = await this.rolesRepository.insertOne({
id: this.idService.gen(date.getTime()), id: this.idService.gen(date.getTime()),
updatedAt: date, updatedAt: date,
lastUsedAt: date, lastUsedAt: date,
@ -576,7 +576,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
canEditMembersByModerator: values.canEditMembersByModerator, canEditMembersByModerator: values.canEditMembersByModerator,
displayOrder: values.displayOrder, displayOrder: values.displayOrder,
policies: values.policies, policies: values.policies,
}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0])); });
this.globalEventService.publishInternalEvent('roleCreated', created); this.globalEventService.publishInternalEvent('roleCreated', created);

View File

@ -517,7 +517,7 @@ export class UserFollowingService implements OnModuleInit {
followerId: follower.id, followerId: follower.id,
}); });
const followRequest = await this.followRequestsRepository.insert({ const followRequest = await this.followRequestsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
followerId: follower.id, followerId: follower.id,
followeeId: followee.id, followeeId: followee.id,
@ -531,7 +531,7 @@ export class UserFollowingService implements OnModuleInit {
followeeHost: followee.host, followeeHost: followee.host,
followeeInbox: this.userEntityService.isRemoteUser(followee) ? followee.inbox : undefined, followeeInbox: this.userEntityService.isRemoteUser(followee) ? followee.inbox : undefined,
followeeSharedInbox: this.userEntityService.isRemoteUser(followee) ? followee.sharedInbox : undefined, followeeSharedInbox: this.userEntityService.isRemoteUser(followee) ? followee.sharedInbox : undefined,
}).then(x => this.followRequestsRepository.findOneByOrFail(x.identifiers[0])); });
// Publish receiveRequest event // Publish receiveRequest event
if (this.userEntityService.isLocalUser(followee)) { if (this.userEntityService.isLocalUser(followee)) {

View File

@ -407,7 +407,7 @@ export class ApNoteService {
this.logger.info(`register emoji host=${host}, name=${name}`); this.logger.info(`register emoji host=${host}, name=${name}`);
return await this.emojisRepository.insert({ return await this.emojisRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
host, host,
name, name,
@ -416,7 +416,7 @@ export class ApNoteService {
publicUrl: tag.icon.url, publicUrl: tag.icon.url,
updatedAt: new Date(), updatedAt: new Date(),
aliases: [], aliases: [],
}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0])); });
})); }));
} }
} }

View File

@ -14,7 +14,8 @@ import { EntitySchema, LessThan, Between } from 'typeorm';
import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc/prelude/time.js'; import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc/prelude/time.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type { Repository, DataSource } from 'typeorm'; import { MiRepository, miRepository } from '@/models/_.js';
import type { DataSource, Repository } from 'typeorm';
const COLUMN_PREFIX = '___' as const; const COLUMN_PREFIX = '___' as const;
const UNIQUE_TEMP_COLUMN_PREFIX = 'unique_temp___' as const; const UNIQUE_TEMP_COLUMN_PREFIX = 'unique_temp___' as const;
@ -145,10 +146,10 @@ export default abstract class Chart<T extends Schema> {
group: string | null; group: string | null;
}[] = []; }[] = [];
// ↓にしたいけどfindOneとかで型エラーになる // ↓にしたいけどfindOneとかで型エラーになる
//private repositoryForHour: Repository<RawRecord<T>>; //private repositoryForHour: Repository<RawRecord<T>> & MiRepository<RawRecord<T>>;
//private repositoryForDay: Repository<RawRecord<T>>; //private repositoryForDay: Repository<RawRecord<T>> & MiRepository<RawRecord<T>>;
private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }>; private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>;
private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }>; private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>;
/** /**
* 1(CASCADE削除などアプリケーション側で感知できない変動によるズレの修正用) * 1(CASCADE削除などアプリケーション側で感知できない変動によるズレの修正用)
@ -211,6 +212,10 @@ export default abstract class Chart<T extends Schema> {
} { } {
const createEntity = (span: 'hour' | 'day'): EntitySchema => new EntitySchema({ const createEntity = (span: 'hour' | 'day'): EntitySchema => new EntitySchema({
name: name:
span === 'hour' ? `ChartX${name}` :
span === 'day' ? `ChartDayX${name}` :
new Error('not happen') as never,
tableName:
span === 'hour' ? `__chart__${camelToSnake(name)}` : span === 'hour' ? `__chart__${camelToSnake(name)}` :
span === 'day' ? `__chart_day__${camelToSnake(name)}` : span === 'day' ? `__chart_day__${camelToSnake(name)}` :
new Error('not happen') as never, new Error('not happen') as never,
@ -271,8 +276,8 @@ export default abstract class Chart<T extends Schema> {
this.logger = logger; this.logger = logger;
const { hour, day } = Chart.schemaToEntity(name, schema, grouped); const { hour, day } = Chart.schemaToEntity(name, schema, grouped);
this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour); this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>);
this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day); this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>);
} }
@bindThis @bindThis
@ -387,11 +392,11 @@ export default abstract class Chart<T extends Schema> {
} }
// 新規ログ挿入 // 新規ログ挿入
log = await repository.insert({ log = await repository.insertOne({
date: date, date: date,
...(group ? { group: group } : {}), ...(group ? { group: group } : {}),
...columns, ...columns,
}).then(x => repository.findOneByOrFail(x.identifiers[0])) as RawRecord<T>; }) as RawRecord<T>;
this.logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`); this.logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`);

View File

@ -5,409 +5,409 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; 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 { DataSource } from 'typeorm';
import type { Provider } from '@nestjs/common'; import type { Provider } from '@nestjs/common';
const $usersRepository: Provider = { const $usersRepository: Provider = {
provide: DI.usersRepository, provide: DI.usersRepository,
useFactory: (db: DataSource) => db.getRepository(MiUser), useFactory: (db: DataSource) => db.getRepository(MiUser).extend(miRepository as MiRepository<MiUser>),
inject: [DI.db], inject: [DI.db],
}; };
const $notesRepository: Provider = { const $notesRepository: Provider = {
provide: DI.notesRepository, provide: DI.notesRepository,
useFactory: (db: DataSource) => db.getRepository(MiNote), useFactory: (db: DataSource) => db.getRepository(MiNote).extend(miRepository as MiRepository<MiNote>),
inject: [DI.db], inject: [DI.db],
}; };
const $announcementsRepository: Provider = { const $announcementsRepository: Provider = {
provide: DI.announcementsRepository, provide: DI.announcementsRepository,
useFactory: (db: DataSource) => db.getRepository(MiAnnouncement), useFactory: (db: DataSource) => db.getRepository(MiAnnouncement).extend(miRepository as MiRepository<MiAnnouncement>),
inject: [DI.db], inject: [DI.db],
}; };
const $announcementReadsRepository: Provider = { const $announcementReadsRepository: Provider = {
provide: DI.announcementReadsRepository, provide: DI.announcementReadsRepository,
useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead), useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead).extend(miRepository as MiRepository<MiAnnouncementRead>),
inject: [DI.db], inject: [DI.db],
}; };
const $appsRepository: Provider = { const $appsRepository: Provider = {
provide: DI.appsRepository, provide: DI.appsRepository,
useFactory: (db: DataSource) => db.getRepository(MiApp), useFactory: (db: DataSource) => db.getRepository(MiApp).extend(miRepository as MiRepository<MiApp>),
inject: [DI.db], inject: [DI.db],
}; };
const $avatarDecorationsRepository: Provider = { const $avatarDecorationsRepository: Provider = {
provide: DI.avatarDecorationsRepository, provide: DI.avatarDecorationsRepository,
useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration), useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration).extend(miRepository as MiRepository<MiAvatarDecoration>),
inject: [DI.db], inject: [DI.db],
}; };
const $noteFavoritesRepository: Provider = { const $noteFavoritesRepository: Provider = {
provide: DI.noteFavoritesRepository, provide: DI.noteFavoritesRepository,
useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite), useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite).extend(miRepository as MiRepository<MiNoteFavorite>),
inject: [DI.db], inject: [DI.db],
}; };
const $noteThreadMutingsRepository: Provider = { const $noteThreadMutingsRepository: Provider = {
provide: DI.noteThreadMutingsRepository, provide: DI.noteThreadMutingsRepository,
useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting), useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting).extend(miRepository as MiRepository<MiNoteThreadMuting>),
inject: [DI.db], inject: [DI.db],
}; };
const $noteReactionsRepository: Provider = { const $noteReactionsRepository: Provider = {
provide: DI.noteReactionsRepository, provide: DI.noteReactionsRepository,
useFactory: (db: DataSource) => db.getRepository(MiNoteReaction), useFactory: (db: DataSource) => db.getRepository(MiNoteReaction).extend(miRepository as MiRepository<MiNoteReaction>),
inject: [DI.db], inject: [DI.db],
}; };
const $noteUnreadsRepository: Provider = { const $noteUnreadsRepository: Provider = {
provide: DI.noteUnreadsRepository, provide: DI.noteUnreadsRepository,
useFactory: (db: DataSource) => db.getRepository(MiNoteUnread), useFactory: (db: DataSource) => db.getRepository(MiNoteUnread).extend(miRepository as MiRepository<MiNoteUnread>),
inject: [DI.db], inject: [DI.db],
}; };
const $pollsRepository: Provider = { const $pollsRepository: Provider = {
provide: DI.pollsRepository, provide: DI.pollsRepository,
useFactory: (db: DataSource) => db.getRepository(MiPoll), useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository<MiPoll>),
inject: [DI.db], inject: [DI.db],
}; };
const $pollVotesRepository: Provider = { const $pollVotesRepository: Provider = {
provide: DI.pollVotesRepository, provide: DI.pollVotesRepository,
useFactory: (db: DataSource) => db.getRepository(MiPollVote), useFactory: (db: DataSource) => db.getRepository(MiPollVote).extend(miRepository as MiRepository<MiPollVote>),
inject: [DI.db], inject: [DI.db],
}; };
const $userProfilesRepository: Provider = { const $userProfilesRepository: Provider = {
provide: DI.userProfilesRepository, provide: DI.userProfilesRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserProfile), useFactory: (db: DataSource) => db.getRepository(MiUserProfile).extend(miRepository as MiRepository<MiUserProfile>),
inject: [DI.db], inject: [DI.db],
}; };
const $userKeypairsRepository: Provider = { const $userKeypairsRepository: Provider = {
provide: DI.userKeypairsRepository, provide: DI.userKeypairsRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserKeypair), useFactory: (db: DataSource) => db.getRepository(MiUserKeypair).extend(miRepository as MiRepository<MiUserKeypair>),
inject: [DI.db], inject: [DI.db],
}; };
const $userPendingsRepository: Provider = { const $userPendingsRepository: Provider = {
provide: DI.userPendingsRepository, provide: DI.userPendingsRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserPending), useFactory: (db: DataSource) => db.getRepository(MiUserPending).extend(miRepository as MiRepository<MiUserPending>),
inject: [DI.db], inject: [DI.db],
}; };
const $userSecurityKeysRepository: Provider = { const $userSecurityKeysRepository: Provider = {
provide: DI.userSecurityKeysRepository, provide: DI.userSecurityKeysRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey), useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey).extend(miRepository as MiRepository<MiUserSecurityKey>),
inject: [DI.db], inject: [DI.db],
}; };
const $userPublickeysRepository: Provider = { const $userPublickeysRepository: Provider = {
provide: DI.userPublickeysRepository, provide: DI.userPublickeysRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserPublickey), useFactory: (db: DataSource) => db.getRepository(MiUserPublickey).extend(miRepository as MiRepository<MiUserPublickey>),
inject: [DI.db], inject: [DI.db],
}; };
const $userListsRepository: Provider = { const $userListsRepository: Provider = {
provide: DI.userListsRepository, provide: DI.userListsRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserList), useFactory: (db: DataSource) => db.getRepository(MiUserList).extend(miRepository as MiRepository<MiUserList>),
inject: [DI.db], inject: [DI.db],
}; };
const $userListFavoritesRepository: Provider = { const $userListFavoritesRepository: Provider = {
provide: DI.userListFavoritesRepository, provide: DI.userListFavoritesRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite), useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite).extend(miRepository as MiRepository<MiUserListFavorite>),
inject: [DI.db], inject: [DI.db],
}; };
const $userListMembershipsRepository: Provider = { const $userListMembershipsRepository: Provider = {
provide: DI.userListMembershipsRepository, provide: DI.userListMembershipsRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserListMembership), useFactory: (db: DataSource) => db.getRepository(MiUserListMembership).extend(miRepository as MiRepository<MiUserListMembership>),
inject: [DI.db], inject: [DI.db],
}; };
const $userNotePiningsRepository: Provider = { const $userNotePiningsRepository: Provider = {
provide: DI.userNotePiningsRepository, provide: DI.userNotePiningsRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserNotePining), useFactory: (db: DataSource) => db.getRepository(MiUserNotePining).extend(miRepository as MiRepository<MiUserNotePining>),
inject: [DI.db], inject: [DI.db],
}; };
const $userIpsRepository: Provider = { const $userIpsRepository: Provider = {
provide: DI.userIpsRepository, provide: DI.userIpsRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserIp), useFactory: (db: DataSource) => db.getRepository(MiUserIp).extend(miRepository as MiRepository<MiUserIp>),
inject: [DI.db], inject: [DI.db],
}; };
const $usedUsernamesRepository: Provider = { const $usedUsernamesRepository: Provider = {
provide: DI.usedUsernamesRepository, provide: DI.usedUsernamesRepository,
useFactory: (db: DataSource) => db.getRepository(MiUsedUsername), useFactory: (db: DataSource) => db.getRepository(MiUsedUsername).extend(miRepository as MiRepository<MiUsedUsername>),
inject: [DI.db], inject: [DI.db],
}; };
const $followingsRepository: Provider = { const $followingsRepository: Provider = {
provide: DI.followingsRepository, provide: DI.followingsRepository,
useFactory: (db: DataSource) => db.getRepository(MiFollowing), useFactory: (db: DataSource) => db.getRepository(MiFollowing).extend(miRepository as MiRepository<MiFollowing>),
inject: [DI.db], inject: [DI.db],
}; };
const $followRequestsRepository: Provider = { const $followRequestsRepository: Provider = {
provide: DI.followRequestsRepository, provide: DI.followRequestsRepository,
useFactory: (db: DataSource) => db.getRepository(MiFollowRequest), useFactory: (db: DataSource) => db.getRepository(MiFollowRequest).extend(miRepository as MiRepository<MiFollowRequest>),
inject: [DI.db], inject: [DI.db],
}; };
const $instancesRepository: Provider = { const $instancesRepository: Provider = {
provide: DI.instancesRepository, provide: DI.instancesRepository,
useFactory: (db: DataSource) => db.getRepository(MiInstance), useFactory: (db: DataSource) => db.getRepository(MiInstance).extend(miRepository as MiRepository<MiInstance>),
inject: [DI.db], inject: [DI.db],
}; };
const $emojisRepository: Provider = { const $emojisRepository: Provider = {
provide: DI.emojisRepository, provide: DI.emojisRepository,
useFactory: (db: DataSource) => db.getRepository(MiEmoji), useFactory: (db: DataSource) => db.getRepository(MiEmoji).extend(miRepository as MiRepository<MiEmoji>),
inject: [DI.db], inject: [DI.db],
}; };
const $driveFilesRepository: Provider = { const $driveFilesRepository: Provider = {
provide: DI.driveFilesRepository, provide: DI.driveFilesRepository,
useFactory: (db: DataSource) => db.getRepository(MiDriveFile), useFactory: (db: DataSource) => db.getRepository(MiDriveFile).extend(miRepository as MiRepository<MiDriveFile>),
inject: [DI.db], inject: [DI.db],
}; };
const $driveFoldersRepository: Provider = { const $driveFoldersRepository: Provider = {
provide: DI.driveFoldersRepository, provide: DI.driveFoldersRepository,
useFactory: (db: DataSource) => db.getRepository(MiDriveFolder), useFactory: (db: DataSource) => db.getRepository(MiDriveFolder).extend(miRepository as MiRepository<MiDriveFolder>),
inject: [DI.db], inject: [DI.db],
}; };
const $metasRepository: Provider = { const $metasRepository: Provider = {
provide: DI.metasRepository, provide: DI.metasRepository,
useFactory: (db: DataSource) => db.getRepository(MiMeta), useFactory: (db: DataSource) => db.getRepository(MiMeta).extend(miRepository as MiRepository<MiMeta>),
inject: [DI.db], inject: [DI.db],
}; };
const $mutingsRepository: Provider = { const $mutingsRepository: Provider = {
provide: DI.mutingsRepository, provide: DI.mutingsRepository,
useFactory: (db: DataSource) => db.getRepository(MiMuting), useFactory: (db: DataSource) => db.getRepository(MiMuting).extend(miRepository as MiRepository<MiMuting>),
inject: [DI.db], inject: [DI.db],
}; };
const $renoteMutingsRepository: Provider = { const $renoteMutingsRepository: Provider = {
provide: DI.renoteMutingsRepository, provide: DI.renoteMutingsRepository,
useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting), useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting).extend(miRepository as MiRepository<MiRenoteMuting>),
inject: [DI.db], inject: [DI.db],
}; };
const $blockingsRepository: Provider = { const $blockingsRepository: Provider = {
provide: DI.blockingsRepository, provide: DI.blockingsRepository,
useFactory: (db: DataSource) => db.getRepository(MiBlocking), useFactory: (db: DataSource) => db.getRepository(MiBlocking).extend(miRepository as MiRepository<MiBlocking>),
inject: [DI.db], inject: [DI.db],
}; };
const $swSubscriptionsRepository: Provider = { const $swSubscriptionsRepository: Provider = {
provide: DI.swSubscriptionsRepository, provide: DI.swSubscriptionsRepository,
useFactory: (db: DataSource) => db.getRepository(MiSwSubscription), useFactory: (db: DataSource) => db.getRepository(MiSwSubscription).extend(miRepository as MiRepository<MiSwSubscription>),
inject: [DI.db], inject: [DI.db],
}; };
const $hashtagsRepository: Provider = { const $hashtagsRepository: Provider = {
provide: DI.hashtagsRepository, provide: DI.hashtagsRepository,
useFactory: (db: DataSource) => db.getRepository(MiHashtag), useFactory: (db: DataSource) => db.getRepository(MiHashtag).extend(miRepository as MiRepository<MiHashtag>),
inject: [DI.db], inject: [DI.db],
}; };
const $abuseUserReportsRepository: Provider = { const $abuseUserReportsRepository: Provider = {
provide: DI.abuseUserReportsRepository, provide: DI.abuseUserReportsRepository,
useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport), useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport).extend(miRepository as MiRepository<MiAbuseUserReport>),
inject: [DI.db], inject: [DI.db],
}; };
const $registrationTicketsRepository: Provider = { const $registrationTicketsRepository: Provider = {
provide: DI.registrationTicketsRepository, provide: DI.registrationTicketsRepository,
useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket), useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket).extend(miRepository as MiRepository<MiRegistrationTicket>),
inject: [DI.db], inject: [DI.db],
}; };
const $authSessionsRepository: Provider = { const $authSessionsRepository: Provider = {
provide: DI.authSessionsRepository, provide: DI.authSessionsRepository,
useFactory: (db: DataSource) => db.getRepository(MiAuthSession), useFactory: (db: DataSource) => db.getRepository(MiAuthSession).extend(miRepository as MiRepository<MiAuthSession>),
inject: [DI.db], inject: [DI.db],
}; };
const $accessTokensRepository: Provider = { const $accessTokensRepository: Provider = {
provide: DI.accessTokensRepository, provide: DI.accessTokensRepository,
useFactory: (db: DataSource) => db.getRepository(MiAccessToken), useFactory: (db: DataSource) => db.getRepository(MiAccessToken).extend(miRepository as MiRepository<MiAccessToken>),
inject: [DI.db], inject: [DI.db],
}; };
const $signinsRepository: Provider = { const $signinsRepository: Provider = {
provide: DI.signinsRepository, provide: DI.signinsRepository,
useFactory: (db: DataSource) => db.getRepository(MiSignin), useFactory: (db: DataSource) => db.getRepository(MiSignin).extend(miRepository as MiRepository<MiSignin>),
inject: [DI.db], inject: [DI.db],
}; };
const $pagesRepository: Provider = { const $pagesRepository: Provider = {
provide: DI.pagesRepository, provide: DI.pagesRepository,
useFactory: (db: DataSource) => db.getRepository(MiPage), useFactory: (db: DataSource) => db.getRepository(MiPage).extend(miRepository as MiRepository<MiPage>),
inject: [DI.db], inject: [DI.db],
}; };
const $pageLikesRepository: Provider = { const $pageLikesRepository: Provider = {
provide: DI.pageLikesRepository, provide: DI.pageLikesRepository,
useFactory: (db: DataSource) => db.getRepository(MiPageLike), useFactory: (db: DataSource) => db.getRepository(MiPageLike).extend(miRepository as MiRepository<MiPageLike>),
inject: [DI.db], inject: [DI.db],
}; };
const $galleryPostsRepository: Provider = { const $galleryPostsRepository: Provider = {
provide: DI.galleryPostsRepository, provide: DI.galleryPostsRepository,
useFactory: (db: DataSource) => db.getRepository(MiGalleryPost), useFactory: (db: DataSource) => db.getRepository(MiGalleryPost).extend(miRepository as MiRepository<MiGalleryPost>),
inject: [DI.db], inject: [DI.db],
}; };
const $galleryLikesRepository: Provider = { const $galleryLikesRepository: Provider = {
provide: DI.galleryLikesRepository, provide: DI.galleryLikesRepository,
useFactory: (db: DataSource) => db.getRepository(MiGalleryLike), useFactory: (db: DataSource) => db.getRepository(MiGalleryLike).extend(miRepository as MiRepository<MiGalleryLike>),
inject: [DI.db], inject: [DI.db],
}; };
const $moderationLogsRepository: Provider = { const $moderationLogsRepository: Provider = {
provide: DI.moderationLogsRepository, provide: DI.moderationLogsRepository,
useFactory: (db: DataSource) => db.getRepository(MiModerationLog), useFactory: (db: DataSource) => db.getRepository(MiModerationLog).extend(miRepository as MiRepository<MiModerationLog>),
inject: [DI.db], inject: [DI.db],
}; };
const $clipsRepository: Provider = { const $clipsRepository: Provider = {
provide: DI.clipsRepository, provide: DI.clipsRepository,
useFactory: (db: DataSource) => db.getRepository(MiClip), useFactory: (db: DataSource) => db.getRepository(MiClip).extend(miRepository as MiRepository<MiClip>),
inject: [DI.db], inject: [DI.db],
}; };
const $clipNotesRepository: Provider = { const $clipNotesRepository: Provider = {
provide: DI.clipNotesRepository, provide: DI.clipNotesRepository,
useFactory: (db: DataSource) => db.getRepository(MiClipNote), useFactory: (db: DataSource) => db.getRepository(MiClipNote).extend(miRepository as MiRepository<MiClipNote>),
inject: [DI.db], inject: [DI.db],
}; };
const $clipFavoritesRepository: Provider = { const $clipFavoritesRepository: Provider = {
provide: DI.clipFavoritesRepository, provide: DI.clipFavoritesRepository,
useFactory: (db: DataSource) => db.getRepository(MiClipFavorite), useFactory: (db: DataSource) => db.getRepository(MiClipFavorite).extend(miRepository as MiRepository<MiClipFavorite>),
inject: [DI.db], inject: [DI.db],
}; };
const $antennasRepository: Provider = { const $antennasRepository: Provider = {
provide: DI.antennasRepository, provide: DI.antennasRepository,
useFactory: (db: DataSource) => db.getRepository(MiAntenna), useFactory: (db: DataSource) => db.getRepository(MiAntenna).extend(miRepository as MiRepository<MiAntenna>),
inject: [DI.db], inject: [DI.db],
}; };
const $promoNotesRepository: Provider = { const $promoNotesRepository: Provider = {
provide: DI.promoNotesRepository, provide: DI.promoNotesRepository,
useFactory: (db: DataSource) => db.getRepository(MiPromoNote), useFactory: (db: DataSource) => db.getRepository(MiPromoNote).extend(miRepository as MiRepository<MiPromoNote>),
inject: [DI.db], inject: [DI.db],
}; };
const $promoReadsRepository: Provider = { const $promoReadsRepository: Provider = {
provide: DI.promoReadsRepository, provide: DI.promoReadsRepository,
useFactory: (db: DataSource) => db.getRepository(MiPromoRead), useFactory: (db: DataSource) => db.getRepository(MiPromoRead).extend(miRepository as MiRepository<MiPromoRead>),
inject: [DI.db], inject: [DI.db],
}; };
const $relaysRepository: Provider = { const $relaysRepository: Provider = {
provide: DI.relaysRepository, provide: DI.relaysRepository,
useFactory: (db: DataSource) => db.getRepository(MiRelay), useFactory: (db: DataSource) => db.getRepository(MiRelay).extend(miRepository as MiRepository<MiRelay>),
inject: [DI.db], inject: [DI.db],
}; };
const $channelsRepository: Provider = { const $channelsRepository: Provider = {
provide: DI.channelsRepository, provide: DI.channelsRepository,
useFactory: (db: DataSource) => db.getRepository(MiChannel), useFactory: (db: DataSource) => db.getRepository(MiChannel).extend(miRepository as MiRepository<MiChannel>),
inject: [DI.db], inject: [DI.db],
}; };
const $channelFollowingsRepository: Provider = { const $channelFollowingsRepository: Provider = {
provide: DI.channelFollowingsRepository, provide: DI.channelFollowingsRepository,
useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing), useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing).extend(miRepository as MiRepository<MiChannelFollowing>),
inject: [DI.db], inject: [DI.db],
}; };
const $channelFavoritesRepository: Provider = { const $channelFavoritesRepository: Provider = {
provide: DI.channelFavoritesRepository, provide: DI.channelFavoritesRepository,
useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite), useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite).extend(miRepository as MiRepository<MiChannelFavorite>),
inject: [DI.db], inject: [DI.db],
}; };
const $registryItemsRepository: Provider = { const $registryItemsRepository: Provider = {
provide: DI.registryItemsRepository, provide: DI.registryItemsRepository,
useFactory: (db: DataSource) => db.getRepository(MiRegistryItem), useFactory: (db: DataSource) => db.getRepository(MiRegistryItem).extend(miRepository as MiRepository<MiRegistryItem>),
inject: [DI.db], inject: [DI.db],
}; };
const $webhooksRepository: Provider = { const $webhooksRepository: Provider = {
provide: DI.webhooksRepository, provide: DI.webhooksRepository,
useFactory: (db: DataSource) => db.getRepository(MiWebhook), useFactory: (db: DataSource) => db.getRepository(MiWebhook).extend(miRepository as MiRepository<MiWebhook>),
inject: [DI.db], inject: [DI.db],
}; };
const $adsRepository: Provider = { const $adsRepository: Provider = {
provide: DI.adsRepository, provide: DI.adsRepository,
useFactory: (db: DataSource) => db.getRepository(MiAd), useFactory: (db: DataSource) => db.getRepository(MiAd).extend(miRepository as MiRepository<MiAd>),
inject: [DI.db], inject: [DI.db],
}; };
const $passwordResetRequestsRepository: Provider = { const $passwordResetRequestsRepository: Provider = {
provide: DI.passwordResetRequestsRepository, provide: DI.passwordResetRequestsRepository,
useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest), useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest).extend(miRepository as MiRepository<MiPasswordResetRequest>),
inject: [DI.db], inject: [DI.db],
}; };
const $retentionAggregationsRepository: Provider = { const $retentionAggregationsRepository: Provider = {
provide: DI.retentionAggregationsRepository, provide: DI.retentionAggregationsRepository,
useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation), useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation).extend(miRepository as MiRepository<MiRetentionAggregation>),
inject: [DI.db], inject: [DI.db],
}; };
const $flashsRepository: Provider = { const $flashsRepository: Provider = {
provide: DI.flashsRepository, provide: DI.flashsRepository,
useFactory: (db: DataSource) => db.getRepository(MiFlash), useFactory: (db: DataSource) => db.getRepository(MiFlash).extend(miRepository as MiRepository<MiFlash>),
inject: [DI.db], inject: [DI.db],
}; };
const $flashLikesRepository: Provider = { const $flashLikesRepository: Provider = {
provide: DI.flashLikesRepository, provide: DI.flashLikesRepository,
useFactory: (db: DataSource) => db.getRepository(MiFlashLike), useFactory: (db: DataSource) => db.getRepository(MiFlashLike).extend(miRepository as MiRepository<MiFlashLike>),
inject: [DI.db], inject: [DI.db],
}; };
const $rolesRepository: Provider = { const $rolesRepository: Provider = {
provide: DI.rolesRepository, provide: DI.rolesRepository,
useFactory: (db: DataSource) => db.getRepository(MiRole), useFactory: (db: DataSource) => db.getRepository(MiRole).extend(miRepository as MiRepository<MiRole>),
inject: [DI.db], inject: [DI.db],
}; };
const $roleAssignmentsRepository: Provider = { const $roleAssignmentsRepository: Provider = {
provide: DI.roleAssignmentsRepository, provide: DI.roleAssignmentsRepository,
useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment), useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment).extend(miRepository as MiRepository<MiRoleAssignment>),
inject: [DI.db], inject: [DI.db],
}; };
const $userMemosRepository: Provider = { const $userMemosRepository: Provider = {
provide: DI.userMemosRepository, provide: DI.userMemosRepository,
useFactory: (db: DataSource) => db.getRepository(MiUserMemo), useFactory: (db: DataSource) => db.getRepository(MiUserMemo).extend(miRepository as MiRepository<MiUserMemo>),
inject: [DI.db], inject: [DI.db],
}; };
const $bubbleGameRecordsRepository: Provider = { const $bubbleGameRecordsRepository: Provider = {
provide: DI.bubbleGameRecordsRepository, provide: DI.bubbleGameRecordsRepository,
useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord), useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord).extend(miRepository as MiRepository<MiBubbleGameRecord>),
inject: [DI.db], inject: [DI.db],
}; };
const $reversiGamesRepository: Provider = { const $reversiGamesRepository: Provider = {
provide: DI.reversiGamesRepository, provide: DI.reversiGamesRepository,
useFactory: (db: DataSource) => db.getRepository(MiReversiGame), useFactory: (db: DataSource) => db.getRepository(MiReversiGame).extend(miRepository as MiRepository<MiReversiGame>),
inject: [DI.db], inject: [DI.db],
}; };

View File

@ -3,6 +3,13 @@
* SPDX-License-Identifier: AGPL-3.0-only * 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 { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import { MiAccessToken } from '@/models/AccessToken.js'; import { MiAccessToken } from '@/models/AccessToken.js';
import { MiAd } from '@/models/Ad.js'; import { MiAd } from '@/models/Ad.js';
@ -70,8 +77,70 @@ import { MiFlashLike } from '@/models/FlashLike.js';
import { MiUserListFavorite } from '@/models/UserListFavorite.js'; import { MiUserListFavorite } from '@/models/UserListFavorite.js';
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js'; import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
import { MiReversiGame } from '@/models/ReversiGame.js'; import { MiReversiGame } from '@/models/ReversiGame.js';
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
import type { Repository } from 'typeorm'; export interface MiRepository<T extends ObjectLiteral> {
createTableColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
createTableColumnNamesWithPrimaryKey(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): 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<ObjectLiteral>;
export { export {
MiAbuseUserReport, MiAbuseUserReport,
@ -143,70 +212,70 @@ export {
MiReversiGame, MiReversiGame,
}; };
export type AbuseUserReportsRepository = Repository<MiAbuseUserReport>; export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
export type AccessTokensRepository = Repository<MiAccessToken>; export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>;
export type AdsRepository = Repository<MiAd>; export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>;
export type AnnouncementsRepository = Repository<MiAnnouncement>; export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>;
export type AnnouncementReadsRepository = Repository<MiAnnouncementRead>; export type AnnouncementReadsRepository = Repository<MiAnnouncementRead> & MiRepository<MiAnnouncementRead>;
export type AntennasRepository = Repository<MiAntenna>; export type AntennasRepository = Repository<MiAntenna> & MiRepository<MiAntenna>;
export type AppsRepository = Repository<MiApp>; export type AppsRepository = Repository<MiApp> & MiRepository<MiApp>;
export type AvatarDecorationsRepository = Repository<MiAvatarDecoration>; export type AvatarDecorationsRepository = Repository<MiAvatarDecoration> & MiRepository<MiAvatarDecoration>;
export type AuthSessionsRepository = Repository<MiAuthSession>; export type AuthSessionsRepository = Repository<MiAuthSession> & MiRepository<MiAuthSession>;
export type BlockingsRepository = Repository<MiBlocking>; export type BlockingsRepository = Repository<MiBlocking> & MiRepository<MiBlocking>;
export type ChannelFollowingsRepository = Repository<MiChannelFollowing>; export type ChannelFollowingsRepository = Repository<MiChannelFollowing> & MiRepository<MiChannelFollowing>;
export type ChannelFavoritesRepository = Repository<MiChannelFavorite>; export type ChannelFavoritesRepository = Repository<MiChannelFavorite> & MiRepository<MiChannelFavorite>;
export type ClipsRepository = Repository<MiClip>; export type ClipsRepository = Repository<MiClip> & MiRepository<MiClip>;
export type ClipNotesRepository = Repository<MiClipNote>; export type ClipNotesRepository = Repository<MiClipNote> & MiRepository<MiClipNote>;
export type ClipFavoritesRepository = Repository<MiClipFavorite>; export type ClipFavoritesRepository = Repository<MiClipFavorite> & MiRepository<MiClipFavorite>;
export type DriveFilesRepository = Repository<MiDriveFile>; export type DriveFilesRepository = Repository<MiDriveFile> & MiRepository<MiDriveFile>;
export type DriveFoldersRepository = Repository<MiDriveFolder>; export type DriveFoldersRepository = Repository<MiDriveFolder> & MiRepository<MiDriveFolder>;
export type EmojisRepository = Repository<MiEmoji>; export type EmojisRepository = Repository<MiEmoji> & MiRepository<MiEmoji>;
export type FollowingsRepository = Repository<MiFollowing>; export type FollowingsRepository = Repository<MiFollowing> & MiRepository<MiFollowing>;
export type FollowRequestsRepository = Repository<MiFollowRequest>; export type FollowRequestsRepository = Repository<MiFollowRequest> & MiRepository<MiFollowRequest>;
export type GalleryLikesRepository = Repository<MiGalleryLike>; export type GalleryLikesRepository = Repository<MiGalleryLike> & MiRepository<MiGalleryLike>;
export type GalleryPostsRepository = Repository<MiGalleryPost>; export type GalleryPostsRepository = Repository<MiGalleryPost> & MiRepository<MiGalleryPost>;
export type HashtagsRepository = Repository<MiHashtag>; export type HashtagsRepository = Repository<MiHashtag> & MiRepository<MiHashtag>;
export type InstancesRepository = Repository<MiInstance>; export type InstancesRepository = Repository<MiInstance> & MiRepository<MiInstance>;
export type MetasRepository = Repository<MiMeta>; export type MetasRepository = Repository<MiMeta> & MiRepository<MiMeta>;
export type ModerationLogsRepository = Repository<MiModerationLog>; export type ModerationLogsRepository = Repository<MiModerationLog> & MiRepository<MiModerationLog>;
export type MutingsRepository = Repository<MiMuting>; export type MutingsRepository = Repository<MiMuting> & MiRepository<MiMuting>;
export type RenoteMutingsRepository = Repository<MiRenoteMuting>; export type RenoteMutingsRepository = Repository<MiRenoteMuting> & MiRepository<MiRenoteMuting>;
export type NotesRepository = Repository<MiNote>; export type NotesRepository = Repository<MiNote> & MiRepository<MiNote>;
export type NoteFavoritesRepository = Repository<MiNoteFavorite>; export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>;
export type NoteReactionsRepository = Repository<MiNoteReaction>; export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>;
export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting>; export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>;
export type NoteUnreadsRepository = Repository<MiNoteUnread>; export type NoteUnreadsRepository = Repository<MiNoteUnread> & MiRepository<MiNoteUnread>;
export type PagesRepository = Repository<MiPage>; export type PagesRepository = Repository<MiPage> & MiRepository<MiPage>;
export type PageLikesRepository = Repository<MiPageLike>; export type PageLikesRepository = Repository<MiPageLike> & MiRepository<MiPageLike>;
export type PasswordResetRequestsRepository = Repository<MiPasswordResetRequest>; export type PasswordResetRequestsRepository = Repository<MiPasswordResetRequest> & MiRepository<MiPasswordResetRequest>;
export type PollsRepository = Repository<MiPoll>; export type PollsRepository = Repository<MiPoll> & MiRepository<MiPoll>;
export type PollVotesRepository = Repository<MiPollVote>; export type PollVotesRepository = Repository<MiPollVote> & MiRepository<MiPollVote>;
export type PromoNotesRepository = Repository<MiPromoNote>; export type PromoNotesRepository = Repository<MiPromoNote> & MiRepository<MiPromoNote>;
export type PromoReadsRepository = Repository<MiPromoRead>; export type PromoReadsRepository = Repository<MiPromoRead> & MiRepository<MiPromoRead>;
export type RegistrationTicketsRepository = Repository<MiRegistrationTicket>; export type RegistrationTicketsRepository = Repository<MiRegistrationTicket> & MiRepository<MiRegistrationTicket>;
export type RegistryItemsRepository = Repository<MiRegistryItem>; export type RegistryItemsRepository = Repository<MiRegistryItem> & MiRepository<MiRegistryItem>;
export type RelaysRepository = Repository<MiRelay>; export type RelaysRepository = Repository<MiRelay> & MiRepository<MiRelay>;
export type SigninsRepository = Repository<MiSignin>; export type SigninsRepository = Repository<MiSignin> & MiRepository<MiSignin>;
export type SwSubscriptionsRepository = Repository<MiSwSubscription>; export type SwSubscriptionsRepository = Repository<MiSwSubscription> & MiRepository<MiSwSubscription>;
export type UsedUsernamesRepository = Repository<MiUsedUsername>; export type UsedUsernamesRepository = Repository<MiUsedUsername> & MiRepository<MiUsedUsername>;
export type UsersRepository = Repository<MiUser>; export type UsersRepository = Repository<MiUser> & MiRepository<MiUser>;
export type UserIpsRepository = Repository<MiUserIp>; export type UserIpsRepository = Repository<MiUserIp> & MiRepository<MiUserIp>;
export type UserKeypairsRepository = Repository<MiUserKeypair>; export type UserKeypairsRepository = Repository<MiUserKeypair> & MiRepository<MiUserKeypair>;
export type UserListsRepository = Repository<MiUserList>; export type UserListsRepository = Repository<MiUserList> & MiRepository<MiUserList>;
export type UserListFavoritesRepository = Repository<MiUserListFavorite>; export type UserListFavoritesRepository = Repository<MiUserListFavorite> & MiRepository<MiUserListFavorite>;
export type UserListMembershipsRepository = Repository<MiUserListMembership>; export type UserListMembershipsRepository = Repository<MiUserListMembership> & MiRepository<MiUserListMembership>;
export type UserNotePiningsRepository = Repository<MiUserNotePining>; export type UserNotePiningsRepository = Repository<MiUserNotePining> & MiRepository<MiUserNotePining>;
export type UserPendingsRepository = Repository<MiUserPending>; export type UserPendingsRepository = Repository<MiUserPending> & MiRepository<MiUserPending>;
export type UserProfilesRepository = Repository<MiUserProfile>; export type UserProfilesRepository = Repository<MiUserProfile> & MiRepository<MiUserProfile>;
export type UserPublickeysRepository = Repository<MiUserPublickey>; export type UserPublickeysRepository = Repository<MiUserPublickey> & MiRepository<MiUserPublickey>;
export type UserSecurityKeysRepository = Repository<MiUserSecurityKey>; export type UserSecurityKeysRepository = Repository<MiUserSecurityKey> & MiRepository<MiUserSecurityKey>;
export type WebhooksRepository = Repository<MiWebhook>; export type WebhooksRepository = Repository<MiWebhook> & MiRepository<MiWebhook>;
export type ChannelsRepository = Repository<MiChannel>; export type ChannelsRepository = Repository<MiChannel> & MiRepository<MiChannel>;
export type RetentionAggregationsRepository = Repository<MiRetentionAggregation>; export type RetentionAggregationsRepository = Repository<MiRetentionAggregation> & MiRepository<MiRetentionAggregation>;
export type RolesRepository = Repository<MiRole>; export type RolesRepository = Repository<MiRole> & MiRepository<MiRole>;
export type RoleAssignmentsRepository = Repository<MiRoleAssignment>; export type RoleAssignmentsRepository = Repository<MiRoleAssignment> & MiRepository<MiRoleAssignment>;
export type FlashsRepository = Repository<MiFlash>; export type FlashsRepository = Repository<MiFlash> & MiRepository<MiFlash>;
export type FlashLikesRepository = Repository<MiFlashLike>; export type FlashLikesRepository = Repository<MiFlashLike> & MiRepository<MiFlashLike>;
export type UserMemoRepository = Repository<MiUserMemo>; export type UserMemoRepository = Repository<MiUserMemo> & MiRepository<MiUserMemo>;
export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord>; export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord> & MiRepository<MiBubbleGameRecord>;
export type ReversiGamesRepository = Repository<MiReversiGame>; export type ReversiGamesRepository = Repository<MiReversiGame> & MiRepository<MiReversiGame>;

View File

@ -76,7 +76,7 @@ export class ImportAntennasProcessorService {
this.logger.warn('Validation Failed'); this.logger.warn('Validation Failed');
continue; continue;
} }
const result = await this.antennasRepository.insert({ const result = await this.antennasRepository.insertOne({
id: this.idService.gen(now.getTime()), id: this.idService.gen(now.getTime()),
lastUsedAt: now, lastUsedAt: now,
userId: job.data.user.id, userId: job.data.user.id,
@ -91,7 +91,7 @@ export class ImportAntennasProcessorService {
excludeBots: antenna.excludeBots, excludeBots: antenna.excludeBots,
withReplies: antenna.withReplies, withReplies: antenna.withReplies,
withFile: antenna.withFile, withFile: antenna.withFile,
}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0])); });
this.logger.succ('Antenna created: ' + result.id); this.logger.succ('Antenna created: ' + result.id);
this.globalEventService.publishInternalEvent('antennaCreated', result); this.globalEventService.publishInternalEvent('antennaCreated', result);
} }

View File

@ -79,11 +79,11 @@ export class ImportUserListsProcessorService {
}); });
if (list == null) { if (list == null) {
list = await this.userListsRepository.insert({ list = await this.userListsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: user.id, userId: user.id,
name: listName, name: listName,
}).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0])); });
} }
let target = this.utilityService.isSelfHost(host!) ? await this.usersRepository.findOneBy({ let target = this.utilityService.isSelfHost(host!) ? await this.usersRepository.findOneBy({

View File

@ -29,13 +29,13 @@ export class SigninService {
public signin(request: FastifyRequest, reply: FastifyReply, user: MiLocalUser) { public signin(request: FastifyRequest, reply: FastifyReply, user: MiLocalUser) {
setImmediate(async () => { setImmediate(async () => {
// Append signin history // Append signin history
const record = await this.signinsRepository.insert({ const record = await this.signinsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: user.id, userId: user.id,
ip: request.ip, ip: request.ip,
headers: request.headers as any, headers: request.headers as any,
success: true, success: true,
}).then(x => this.signinsRepository.findOneByOrFail(x.identifiers[0])); });
// Publish signin event // Publish signin event
this.globalEventService.publishMainStream(user.id, 'signin', await this.signinEntityService.pack(record)); this.globalEventService.publishMainStream(user.id, 'signin', await this.signinEntityService.pack(record));

View File

@ -183,13 +183,13 @@ export class SignupApiService {
const salt = await bcrypt.genSalt(8); const salt = await bcrypt.genSalt(8);
const hash = await bcrypt.hash(password, salt); const hash = await bcrypt.hash(password, salt);
const pendingUser = await this.userPendingsRepository.insert({ const pendingUser = await this.userPendingsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
code, code,
email: emailAddress!, email: emailAddress!,
username: username, username: username,
password: hash, password: hash,
}).then(x => this.userPendingsRepository.findOneByOrFail(x.identifiers[0])); });
const link = `${this.config.url}/signup-complete/${code}`; const link = `${this.config.url}/signup-complete/${code}`;

View File

@ -50,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private moderationLogService: ModerationLogService, private moderationLogService: ModerationLogService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const ad = await this.adsRepository.insert({ const ad = await this.adsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
expiresAt: new Date(ps.expiresAt), expiresAt: new Date(ps.expiresAt),
startsAt: new Date(ps.startsAt), startsAt: new Date(ps.startsAt),
@ -61,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
ratio: ps.ratio, ratio: ps.ratio,
place: ps.place, place: ps.place,
memo: ps.memo, memo: ps.memo,
}).then(r => this.adsRepository.findOneByOrFail({ id: r.identifiers[0].id })); });
this.moderationLogService.log(me, 'createAd', { this.moderationLogService.log(me, 'createAd', {
adId: ad.id, adId: ad.id,

View File

@ -66,11 +66,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const ticketsPromises = []; const ticketsPromises = [];
for (let i = 0; i < ps.count; i++) { for (let i = 0; i < ps.count; i++) {
ticketsPromises.push(this.registrationTicketsRepository.insert({ ticketsPromises.push(this.registrationTicketsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : null, expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : null,
code: generateInviteCode(), code: generateInviteCode(),
}).then(x => this.registrationTicketsRepository.findOneByOrFail(x.identifiers[0]))); }));
} }
const tickets = await Promise.all(ticketsPromises); const tickets = await Promise.all(ticketsPromises);

View File

@ -112,7 +112,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const now = new Date(); const now = new Date();
const antenna = await this.antennasRepository.insert({ const antenna = await this.antennasRepository.insertOne({
id: this.idService.gen(now.getTime()), id: this.idService.gen(now.getTime()),
lastUsedAt: now, lastUsedAt: now,
userId: me.id, userId: me.id,
@ -127,7 +127,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
excludeBots: ps.excludeBots, excludeBots: ps.excludeBots,
withReplies: ps.withReplies, withReplies: ps.withReplies,
withFile: ps.withFile, withFile: ps.withFile,
}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0])); });
this.globalEventService.publishInternalEvent('antennaCreated', antenna); this.globalEventService.publishInternalEvent('antennaCreated', antenna);

View File

@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const permission = unique(ps.permission.map(v => v.replace(/^(.+)(\/|-)(read|write)$/, '$3:$1'))); const permission = unique(ps.permission.map(v => v.replace(/^(.+)(\/|-)(read|write)$/, '$3:$1')));
// Create account // Create account
const app = await this.appsRepository.insert({ const app = await this.appsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: me ? me.id : null, userId: me ? me.id : null,
name: ps.name, name: ps.name,
@ -62,7 +62,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
permission, permission,
callbackUrl: ps.callbackUrl, callbackUrl: ps.callbackUrl,
secret: secret, secret: secret,
}).then(x => this.appsRepository.findOneByOrFail(x.identifiers[0])); });
return await this.appEntityService.pack(app, null, { return await this.appEntityService.pack(app, null, {
detail: true, detail: true,

View File

@ -78,11 +78,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const token = randomUUID(); const token = randomUUID();
// Create session token document // Create session token document
const doc = await this.authSessionsRepository.insert({ const doc = await this.authSessionsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
appId: app.id, appId: app.id,
token: token, token: token,
}).then(x => this.authSessionsRepository.findOneByOrFail(x.identifiers[0])); });
return { return {
token: doc.token, token: doc.token,

View File

@ -80,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} }
} }
const channel = await this.channelsRepository.insert({ const channel = await this.channelsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: me.id, userId: me.id,
name: ps.name, name: ps.name,
@ -89,7 +89,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
isSensitive: ps.isSensitive ?? false, isSensitive: ps.isSensitive ?? false,
...(ps.color !== undefined ? { color: ps.color } : {}), ...(ps.color !== undefined ? { color: ps.color } : {}),
allowRenoteToExternal: ps.allowRenoteToExternal ?? true, allowRenoteToExternal: ps.allowRenoteToExternal ?? true,
} as MiChannel).then(x => this.channelsRepository.findOneByOrFail(x.identifiers[0])); } as MiChannel);
return await this.channelEntityService.pack(channel, me); return await this.channelEntityService.pack(channel, me);
}); });

View File

@ -75,12 +75,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} }
// Create folder // Create folder
const folder = await this.driveFoldersRepository.insert({ const folder = await this.driveFoldersRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
name: ps.name, name: ps.name,
parentId: parent !== null ? parent.id : null, parentId: parent !== null ? parent.id : null,
userId: me.id, userId: me.id,
}).then(x => this.driveFoldersRepository.findOneByOrFail(x.identifiers[0])); });
const folderObj = await this.driveFolderEntityService.pack(folder); const folderObj = await this.driveFolderEntityService.pack(folder);

View File

@ -59,7 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private idService: IdService, private idService: IdService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
const flash = await this.flashsRepository.insert({ const flash = await this.flashsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: me.id, userId: me.id,
updatedAt: new Date(), updatedAt: new Date(),
@ -68,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
script: ps.script, script: ps.script,
permissions: ps.permissions, permissions: ps.permissions,
visibility: ps.visibility, visibility: ps.visibility,
}).then(x => this.flashsRepository.findOneByOrFail(x.identifiers[0])); });
return await this.flashEntityService.pack(flash); return await this.flashEntityService.pack(flash);
}); });

View File

@ -76,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new Error(); throw new Error();
} }
const post = await this.galleryPostsRepository.insert(new MiGalleryPost({ const post = await this.galleryPostsRepository.insertOne(new MiGalleryPost({
id: this.idService.gen(), id: this.idService.gen(),
updatedAt: new Date(), updatedAt: new Date(),
title: ps.title, title: ps.title,
@ -84,7 +84,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
userId: me.id, userId: me.id,
isSensitive: ps.isSensitive, isSensitive: ps.isSensitive,
fileIds: files.map(file => file.id), fileIds: files.map(file => file.id),
})).then(x => this.galleryPostsRepository.findOneByOrFail(x.identifiers[0])); }));
return await this.galleryPostEntityService.pack(post, me); return await this.galleryPostEntityService.pack(post, me);
}); });

View File

@ -89,14 +89,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.tooManyWebhooks); throw new ApiError(meta.errors.tooManyWebhooks);
} }
const webhook = await this.webhooksRepository.insert({ const webhook = await this.webhooksRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: me.id, userId: me.id,
name: ps.name, name: ps.name,
url: ps.url, url: ps.url,
secret: ps.secret, secret: ps.secret,
on: ps.on, on: ps.on,
}).then(x => this.webhooksRepository.findOneByOrFail(x.identifiers[0])); });
this.globalEventService.publishInternalEvent('webhookCreated', webhook); this.globalEventService.publishInternalEvent('webhookCreated', webhook);

View File

@ -66,13 +66,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} }
} }
const ticket = await this.registrationTicketsRepository.insert({ const ticket = await this.registrationTicketsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
createdBy: me, createdBy: me,
createdById: me.id, createdById: me.id,
expiresAt: policies.inviteExpirationTime ? new Date(Date.now() + (policies.inviteExpirationTime * 1000 * 60)) : null, expiresAt: policies.inviteExpirationTime ? new Date(Date.now() + (policies.inviteExpirationTime * 1000 * 60)) : null,
code: generateInviteCode(), code: generateInviteCode(),
}).then(x => this.registrationTicketsRepository.findOneByOrFail(x.identifiers[0])); });
return await this.inviteCodeEntityService.pack(ticket, me); return await this.inviteCodeEntityService.pack(ticket, me);
}); });

View File

@ -144,12 +144,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} }
// Create vote // Create vote
const vote = await this.pollVotesRepository.insert({ const vote = await this.pollVotesRepository.insertOne({
id: this.idService.gen(createdAt.getTime()), id: this.idService.gen(createdAt.getTime()),
noteId: note.id, noteId: note.id,
userId: me.id, userId: me.id,
choice: ps.choice, choice: ps.choice,
}).then(x => this.pollVotesRepository.findOneByOrFail(x.identifiers[0])); });
// Increment votes count // Increment votes count
const index = ps.choice + 1; // In SQL, array index is 1 based const index = ps.choice + 1; // In SQL, array index is 1 based

View File

@ -102,7 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} }
}); });
const page = await this.pagesRepository.insert(new MiPage({ const page = await this.pagesRepository.insertOne(new MiPage({
id: this.idService.gen(), id: this.idService.gen(),
updatedAt: new Date(), updatedAt: new Date(),
title: ps.title, title: ps.title,
@ -117,7 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
alignCenter: ps.alignCenter, alignCenter: ps.alignCenter,
hideTitleWhenPinned: ps.hideTitleWhenPinned, hideTitleWhenPinned: ps.hideTitleWhenPinned,
font: ps.font, font: ps.font,
})).then(x => this.pagesRepository.findOneByOrFail(x.identifiers[0])); }));
return await this.pageEntityService.pack(page); return await this.pageEntityService.pack(page);
}); });

View File

@ -104,11 +104,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.tooManyUserLists); throw new ApiError(meta.errors.tooManyUserLists);
} }
const userList = await this.userListsRepository.insert({ const userList = await this.userListsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: me.id, userId: me.id,
name: ps.name, name: ps.name,
} as MiUserList).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0])); } as MiUserList);
const users = (await this.userListMembershipsRepository.findBy({ const users = (await this.userListMembershipsRepository.findBy({
userListId: ps.listId, userListId: ps.listId,

View File

@ -65,11 +65,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.tooManyUserLists); throw new ApiError(meta.errors.tooManyUserLists);
} }
const userList = await this.userListsRepository.insert({ const userList = await this.userListsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
userId: me.id, userId: me.id,
name: ps.name, name: ps.name,
} as MiUserList).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0])); } as MiUserList);
return await this.userListEntityService.pack(userList); return await this.userListEntityService.pack(userList);
}); });

View File

@ -82,14 +82,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.cannotReportAdmin); throw new ApiError(meta.errors.cannotReportAdmin);
} }
const report = await this.abuseUserReportsRepository.insert({ const report = await this.abuseUserReportsRepository.insertOne({
id: this.idService.gen(), id: this.idService.gen(),
targetUserId: user.id, targetUserId: user.id,
targetUserHost: user.host, targetUserHost: user.host,
reporterId: me.id, reporterId: me.id,
reporterHost: null, reporterHost: null,
comment: ps.comment, comment: ps.comment,
}).then(x => this.abuseUserReportsRepository.findOneByOrFail(x.identifiers[0])); });
// Publish event to moderators // Publish event to moderators
setImmediate(async () => { setImmediate(async () => {

View File

@ -9,7 +9,7 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert'; import * as assert from 'assert';
import { loadConfig } from '@/config.js'; import { loadConfig } from '@/config.js';
import { MiUser, UsersRepository } from '@/models/_.js'; import { MiRepository, MiUser, UsersRepository, miRepository } from '@/models/_.js';
import { secureRndstr } from '@/misc/secure-rndstr.js'; import { secureRndstr } from '@/misc/secure-rndstr.js';
import { jobQueue } from '@/boot/common.js'; import { jobQueue } from '@/boot/common.js';
import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js'; import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js';
@ -42,7 +42,7 @@ describe('Account Move', () => {
dave = await signup({ username: 'dave' }); dave = await signup({ username: 'dave' });
eve = await signup({ username: 'eve' }); eve = await signup({ username: 'eve' });
frank = await signup({ username: 'frank' }); frank = await signup({ username: 'frank' });
Users = connection.getRepository(MiUser); Users = connection.getRepository(MiUser).extend(miRepository as MiRepository<MiUser>);
}, 1000 * 60 * 2); }, 1000 * 60 * 2);
afterAll(async () => { afterAll(async () => {

View File

@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import { ReversiMatchResponse } from 'misskey-js/entities.js';
import { api, signup } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('ReversiGame', () => {
let alice: misskey.entities.SignupResponse;
let bob: misskey.entities.SignupResponse;
beforeAll(async () => {
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });
}, 1000 * 60 * 2);
test('matches when alice invites bob and bob accepts', async () => {
const response1 = await api('reversi/match', { userId: bob.id }, alice);
assert.strictEqual(response1.status, 204);
assert.strictEqual(response1.body, null);
const response2 = await api('reversi/match', { userId: alice.id }, bob);
assert.strictEqual(response2.status, 200);
assert.notStrictEqual(response2.body, null);
const body = response2.body as ReversiMatchResponse;
assert.strictEqual(body.user1.id, alice.id);
assert.strictEqual(body.user2.id, bob.id);
});
});