summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--packages/backend/src/models/_.ts65
2 files changed, 3 insertions, 64 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd7f059c30..5310348063 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,8 @@
- Fix: DeepL APIのAPIキー指定方式変更に対応
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1096)
- 内部実装の変更にて対応可能な更新です。Misskey側の設定方法に変更はありません。
+- Fix: DBレプリケーションを利用する環境でクエリーが失敗する問題を修正
+ (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1123)
## 2025.11.0
diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts
index 8c77a225c8..c4528e3a77 100644
--- a/packages/backend/src/models/_.ts
+++ b/packages/backend/src/models/_.ts
@@ -5,18 +5,9 @@
import {
FindOneOptions,
- InsertQueryBuilder,
ObjectLiteral,
- QueryRunner,
Repository,
- SelectQueryBuilder,
} from 'typeorm';
-import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions.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 { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import { MiAccessToken } from '@/models/AccessToken.js';
@@ -96,66 +87,12 @@ import { MiWebhook } from '@/models/Webhook.js';
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
export interface MiRepository<T extends ObjectLiteral> {
- createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
-
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
-
- insertOneImpl(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>, queryRunner?: QueryRunner): Promise<T>;
-
- selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
}
export const miRepository = {
- createTableColumnNames() {
- return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
- },
async insertOne(entity, findOptions?) {
- const opt = this.manager.connection.options as PostgresConnectionOptions;
- if (opt.replication) {
- const queryRunner = this.manager.connection.createQueryRunner('master');
- try {
- return this.insertOneImpl(entity, findOptions, queryRunner);
- } finally {
- await queryRunner.release();
- }
- } else {
- return this.insertOneImpl(entity, findOptions);
- }
- },
- async insertOneImpl(entity, findOptions?, queryRunner?) {
- // ---- insert + returningの結果を共通テーブル式(CTE)に保持するクエリを生成 ----
-
- 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.createTableColumnNames();
- queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
-
- // ---- 共通テーブル式(CTE)から結果を取得 ----
- const builder = this.createQueryBuilder(undefined, queryRunner).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.createTableColumnNames()) {
- selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`);
- }
+ return await this.insert(entity).then(x => this.findOneOrFail({ where: x.identifiers[0], ...findOptions }));
},
} satisfies MiRepository<ObjectLiteral>;