mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-23 00:29:22 +09:00
Compare commits
8 Commits
d761a6a091
...
c59aa4f634
Author | SHA1 | Date | |
---|---|---|---|
|
c59aa4f634 | ||
|
3c81926f71 | ||
|
ca03491301 | ||
|
72e6adf5ab | ||
|
302b227f51 | ||
|
f2c6485a74 | ||
|
e4e3884758 | ||
|
f0c4565787 |
@ -18,7 +18,7 @@
|
|||||||
- Fix: ユーザーのプロフィール画面をアドレス入力などで直接表示した際に概要タブの描画に失敗する問題の修正( #15032 )
|
- Fix: ユーザーのプロフィール画面をアドレス入力などで直接表示した際に概要タブの描画に失敗する問題の修正( #15032 )
|
||||||
- Fix: 起動前の疎通チェックが機能しなくなっていた問題を修正
|
- Fix: 起動前の疎通チェックが機能しなくなっていた問題を修正
|
||||||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/737)
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/737)
|
||||||
|
- Fix: リードレプリカ設定時にレコードの追加・更新・削除を伴うクエリを発行した際はmasterノードで実行されるように調整( #10897 )
|
||||||
|
|
||||||
## 2024.11.0
|
## 2024.11.0
|
||||||
|
|
||||||
|
@ -3,13 +3,20 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder, TypeORMError } from 'typeorm';
|
import {
|
||||||
import { DriverUtils } from 'typeorm/driver/DriverUtils.js';
|
FindOneOptions,
|
||||||
|
InsertQueryBuilder,
|
||||||
|
ObjectLiteral,
|
||||||
|
QueryRunner,
|
||||||
|
Repository,
|
||||||
|
SelectQueryBuilder,
|
||||||
|
} from 'typeorm';
|
||||||
import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
|
import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
|
||||||
import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
|
import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
|
||||||
import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
|
import {
|
||||||
import { ObjectUtils } from 'typeorm/util/ObjectUtils.js';
|
RawSqlResultsToEntityTransformer,
|
||||||
import { OrmUtils } from 'typeorm/util/OrmUtils.js';
|
} from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
|
||||||
|
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions.js';
|
||||||
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
|
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
|
||||||
import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
|
import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
|
||||||
import { MiAccessToken } from '@/models/AccessToken.js';
|
import { MiAccessToken } from '@/models/AccessToken.js';
|
||||||
@ -83,7 +90,11 @@ import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialE
|
|||||||
|
|
||||||
export interface MiRepository<T extends ObjectLiteral> {
|
export interface MiRepository<T extends ObjectLiteral> {
|
||||||
createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
|
createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
|
||||||
|
|
||||||
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
|
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;
|
selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +103,21 @@ export const miRepository = {
|
|||||||
return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
|
return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
|
||||||
},
|
},
|
||||||
async insertOne(entity, findOptions?) {
|
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);
|
const queryBuilder = this.createQueryBuilder().insert().values(entity);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const mainAlias = queryBuilder.expressionMap.mainAlias!;
|
const mainAlias = queryBuilder.expressionMap.mainAlias!;
|
||||||
@ -99,7 +125,9 @@ export const miRepository = {
|
|||||||
mainAlias.name = 't';
|
mainAlias.name = 't';
|
||||||
const columnNames = this.createTableColumnNames();
|
const columnNames = this.createTableColumnNames();
|
||||||
queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
|
queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
|
||||||
const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
|
|
||||||
|
// ---- 共通テーブル式(CTE)から結果を取得 ----
|
||||||
|
const builder = this.createQueryBuilder(undefined, queryRunner).addCommonTableExpression(queryBuilder, 'cte', { columnNames });
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
builder.expressionMap.mainAlias!.tablePath = 'cte';
|
builder.expressionMap.mainAlias!.tablePath = 'cte';
|
||||||
this.selectAliasColumnNames(queryBuilder, builder);
|
this.selectAliasColumnNames(queryBuilder, builder);
|
||||||
@ -197,7 +225,9 @@ export {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
|
export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
|
||||||
export type AbuseReportNotificationRecipientRepository = Repository<MiAbuseReportNotificationRecipient> & MiRepository<MiAbuseReportNotificationRecipient>;
|
export type AbuseReportNotificationRecipientRepository =
|
||||||
|
Repository<MiAbuseReportNotificationRecipient>
|
||||||
|
& MiRepository<MiAbuseReportNotificationRecipient>;
|
||||||
export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>;
|
export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>;
|
||||||
export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>;
|
export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>;
|
||||||
export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>;
|
export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
// https://github.com/typeorm/typeorm/issues/2400
|
// https://github.com/typeorm/typeorm/issues/2400
|
||||||
import pg from 'pg';
|
import pg from 'pg';
|
||||||
import { DataSource, Logger } from 'typeorm';
|
import { DataSource, Logger, type QueryRunner } from 'typeorm';
|
||||||
import * as highlight from 'cli-highlight';
|
import * as highlight from 'cli-highlight';
|
||||||
import { entities as charts } from '@/core/chart/entities.js';
|
import { entities as charts } from '@/core/chart/entities.js';
|
||||||
|
|
||||||
@ -90,6 +90,11 @@ export const dbLogger = new MisskeyLogger('db');
|
|||||||
const sqlLogger = dbLogger.createSubLogger('sql', 'gray');
|
const sqlLogger = dbLogger.createSubLogger('sql', 'gray');
|
||||||
|
|
||||||
class MyCustomLogger implements Logger {
|
class MyCustomLogger implements Logger {
|
||||||
|
constructor(
|
||||||
|
private printReplicationMode?: boolean,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private highlight(sql: string) {
|
private highlight(sql: string) {
|
||||||
return highlight.highlight(sql, {
|
return highlight.highlight(sql, {
|
||||||
@ -98,18 +103,29 @@ class MyCustomLogger implements Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public logQuery(query: string, parameters?: any[]) {
|
private appendPrefixIfNeeded(message: string, opts?: {
|
||||||
sqlLogger.info(this.highlight(query).substring(0, 100));
|
queryRunner?: QueryRunner;
|
||||||
|
}): string {
|
||||||
|
if (this.printReplicationMode && opts?.queryRunner) {
|
||||||
|
return `[${opts.queryRunner.getReplicationMode()}] ${message}`;
|
||||||
|
} else {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public logQueryError(error: string, query: string, parameters?: any[]) {
|
public logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||||
sqlLogger.error(this.highlight(query));
|
sqlLogger.info(this.appendPrefixIfNeeded(this.highlight(query).substring(0, 100), { queryRunner }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public logQuerySlow(time: number, query: string, parameters?: any[]) {
|
public logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||||
sqlLogger.warn(this.highlight(query));
|
sqlLogger.error(this.appendPrefixIfNeeded(this.highlight(query), { queryRunner }));
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public logQuerySlow(time: number, query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||||
|
sqlLogger.warn(this.appendPrefixIfNeeded(this.highlight(query), { queryRunner }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
@ -247,7 +263,7 @@ export function createPostgresDataSource(config: Config) {
|
|||||||
},
|
},
|
||||||
} : false,
|
} : false,
|
||||||
logging: log,
|
logging: log,
|
||||||
logger: log ? new MyCustomLogger() : undefined,
|
logger: log ? new MyCustomLogger(config.dbReplications) : undefined,
|
||||||
maxQueryExecutionTime: 300,
|
maxQueryExecutionTime: 300,
|
||||||
entities: entities,
|
entities: entities,
|
||||||
migrations: ['../../migration/*.js'],
|
migrations: ['../../migration/*.js'],
|
||||||
|
@ -49,7 +49,7 @@ import { genEmbedCode } from '@/scripts/get-embed-code.js';
|
|||||||
import { assertServerContext, serverContext } from '@/server-context.js';
|
import { assertServerContext, serverContext } from '@/server-context.js';
|
||||||
|
|
||||||
// contextは非ログイン状態の情報しかないためログイン時は利用できない
|
// contextは非ログイン状態の情報しかないためログイン時は利用できない
|
||||||
const CTX_CLIP = $i && assertServerContext(serverContext, 'clip') ? serverContext.clip : null;
|
const CTX_CLIP = !$i && assertServerContext(serverContext, 'clip') ? serverContext.clip : null;
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
clipId: string,
|
clipId: string,
|
||||||
|
@ -67,7 +67,7 @@ import { serverContext, assertServerContext } from '@/server-context.js';
|
|||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
|
||||||
// contextは非ログイン状態の情報しかないためログイン時は利用できない
|
// contextは非ログイン状態の情報しかないためログイン時は利用できない
|
||||||
const CTX_NOTE = $i && assertServerContext(serverContext, 'note') ? serverContext.note : null;
|
const CTX_NOTE = !$i && assertServerContext(serverContext, 'note') ? serverContext.note : null;
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
noteId: string;
|
noteId: string;
|
||||||
|
@ -54,7 +54,7 @@ const XGallery = defineAsyncComponent(() => import('./gallery.vue'));
|
|||||||
const XRaw = defineAsyncComponent(() => import('./raw.vue'));
|
const XRaw = defineAsyncComponent(() => import('./raw.vue'));
|
||||||
|
|
||||||
// contextは非ログイン状態の情報しかないためログイン時は利用できない
|
// contextは非ログイン状態の情報しかないためログイン時は利用できない
|
||||||
const CTX_USER = $i && assertServerContext(serverContext, 'user') ? serverContext.user : null;
|
const CTX_USER = !$i && assertServerContext(serverContext, 'user') ? serverContext.user : null;
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
acct: string;
|
acct: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user