fix pre test

This commit is contained in:
samunohito 2024-02-28 22:25:52 +09:00
parent 53f858d736
commit da13426b89
4 changed files with 146 additions and 149 deletions

View File

@ -3,11 +3,10 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
export class OptimizeEmojiIndex1707951601000 { export class OptimizeEmojiIndex1709126576000 {
name = 'OptimizeEmojiIndex1707951601000' name = 'OptimizeEmojiIndex1709126576000'
async up(queryRunner) { async up(queryRunner) {
await queryRunner.query(`CREATE INDEX "IDX_EMOJI_ALIASES_IDS" ON "emoji" using gin ("aliases")`)
await queryRunner.query(`CREATE INDEX "IDX_EMOJI_ROLE_IDS" ON "emoji" using gin ("roleIdsThatCanBeUsedThisEmojiAsReaction")`) await queryRunner.query(`CREATE INDEX "IDX_EMOJI_ROLE_IDS" ON "emoji" using gin ("roleIdsThatCanBeUsedThisEmojiAsReaction")`)
await queryRunner.query(`CREATE INDEX "IDX_EMOJI_CATEGORY" ON "emoji" ("category")`) await queryRunner.query(`CREATE INDEX "IDX_EMOJI_CATEGORY" ON "emoji" ("category")`)
} }
@ -15,6 +14,5 @@ export class OptimizeEmojiIndex1707951601000 {
async down(queryRunner) { async down(queryRunner) {
await queryRunner.query(`DROP INDEX "IDX_EMOJI_CATEGORY"`) await queryRunner.query(`DROP INDEX "IDX_EMOJI_CATEGORY"`)
await queryRunner.query(`DROP INDEX "IDX_EMOJI_ROLE_IDS"`) await queryRunner.query(`DROP INDEX "IDX_EMOJI_ROLE_IDS"`)
await queryRunner.query(`DROP INDEX "IDX_EMOJI_ALIASES_IDS"`)
} }
} }

View File

@ -4,7 +4,7 @@
*/ */
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import { Brackets, In, IsNull, SelectQueryBuilder, WhereExpressionBuilder } from 'typeorm'; import { Brackets, In, IsNull, ObjectLiteral, SelectQueryBuilder, WhereExpressionBuilder } from 'typeorm';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
@ -446,9 +446,9 @@ export class CustomEmojiService implements OnApplicationShutdown {
@bindThis @bindThis
public async fetchEmojis(params?: FetchEmojisParams) { public async fetchEmojis(params?: FetchEmojisParams) {
function multipleWordsToQuery( function multipleWordsToQuery<T extends ObjectLiteral>(
query: string, query: string,
builder: SelectQueryBuilder<MiEmoji>, builder: SelectQueryBuilder<T>,
action: (qb: WhereExpressionBuilder, idx: number, word: string) => void, action: (qb: WhereExpressionBuilder, idx: number, word: string) => void,
) { ) {
const words = query.split(/\s/); const words = query.split(/\s/);
@ -514,12 +514,23 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
if (q.aliases) { if (q.aliases) {
// noIndexScan // noIndexScan
multipleWordsToQuery(q.aliases, builder, (qb, idx, word) => { const subQueryBuilder = builder.subQuery()
qb.orWhere(`emoji.aliases LIKE :aliases${idx}`, Object.fromEntries([[`aliases${idx}`, `%${word}%`]])); .select('COUNT(0)', 'count')
.from(
sq2 => sq2
.select('unnest(subEmoji.aliases)', 'alias')
.addSelect('subEmoji.id', 'id')
.from('emoji', 'subEmoji'),
'aliasTable',
)
.where('"emoji"."id" = "aliasTable"."id"');
multipleWordsToQuery(q.aliases, subQueryBuilder, (qb, idx, word) => {
qb.orWhere(`"aliasTable"."alias" LIKE :aliases${idx}`, Object.fromEntries([[`aliases${idx}`, `%${word}%`]]));
}); });
builder.andWhere(`(${subQueryBuilder.getQuery()}) > 0`);
} }
if (q.category) { if (q.category) {
// noIndexScan
multipleWordsToQuery(q.category, builder, (qb, idx, word) => { multipleWordsToQuery(q.category, builder, (qb, idx, word) => {
qb.orWhere(`emoji.category LIKE :category${idx}`, Object.fromEntries([[`category${idx}`, `%${word}%`]])); qb.orWhere(`emoji.category LIKE :category${idx}`, Object.fromEntries([[`category${idx}`, `%${word}%`]]));
}); });

View File

@ -4,140 +4,132 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<div> <div class="_gaps">
<MkFolder>
<template #icon><i class="ti ti-search"></i></template>
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.searchSettings }}</template>
<template #caption>
{{ i18n.ts._customEmojisManager._gridCommon.searchSettingCaption }}
</template>
<div class="_gaps">
<div :class="[[spMode ? $style.searchAreaSp : $style.searchArea]]">
<MkInput
v-model="queryName"
type="search"
autocapitalize="off"
class="col1 row1"
@enter="onSearchRequest"
>
<template #label>name</template>
</MkInput>
<MkInput
v-model="queryCategory"
type="search"
autocapitalize="off"
class="col2 row1"
@enter="onSearchRequest"
>
<template #label>category</template>
</MkInput>
<MkInput
v-model="queryAliases"
type="search"
autocapitalize="off"
class="col3 row1"
@enter="onSearchRequest"
>
<template #label>aliases</template>
</MkInput>
<MkInput
v-model="queryType"
type="search"
autocapitalize="off"
class="col1 row2"
@enter="onSearchRequest"
>
<template #label>type</template>
</MkInput>
<MkInput
v-model="queryLicense"
type="search"
autocapitalize="off"
class="col2 row2"
@enter="onSearchRequest"
>
<template #label>license</template>
</MkInput>
<MkSelect
v-model="querySensitive"
class="col3 row2"
>
<template #label>sensitive</template>
<option :value="null">-</option>
<option :value="true">true</option>
<option :value="false">false</option>
</MkSelect>
<MkSelect
v-model="queryLocalOnly"
class="col1 row3"
>
<template #label>localOnly</template>
<option :value="null">-</option>
<option :value="true">true</option>
<option :value="false">false</option>
</MkSelect>
<MkInput
v-model="queryUpdatedAtFrom"
type="date"
autocapitalize="off"
class="col2 row3"
@enter="onSearchRequest"
>
<template #label>updatedAt(from)</template>
</MkInput>
<MkInput
v-model="queryUpdatedAtTo"
type="date"
autocapitalize="off"
class="col3 row3"
@enter="onSearchRequest"
>
<template #label>updatedAt(to)</template>
</MkInput>
<MkInput
v-model="queryRolesText"
type="text"
readonly
autocapitalize="off"
class="col1 row4"
@click="onQueryRolesEditClicked"
>
<template #label>role</template>
<template #suffix><span class="ti ti-pencil"/></template>
</MkInput>
</div>
<XSortOrderFolder :sortOrders="sortOrders" @update="onSortOrderUpdate"/>
<div :class="[[spMode ? $style.searchButtonsSp : $style.searchButtons]]">
<MkButton primary @click="onSearchRequest">
{{ i18n.ts.search }}
</MkButton>
<MkButton @click="onQueryResetButtonClicked">
{{ i18n.ts.reset }}
</MkButton>
</div>
</div>
</MkFolder>
<XRegisterLogsFolder :logs="requestLogs"/>
<div v-if="gridItems.length === 0" style="text-align: center"> <div v-if="gridItems.length === 0" style="text-align: center">
{{ i18n.ts._customEmojisManager._local._list.emojisNothing }} {{ i18n.ts._customEmojisManager._local._list.emojisNothing }}
</div> </div>
<div v-else class="_gaps"> <template v-else>
<MkFolder>
<template #icon><i class="ti ti-search"></i></template>
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.searchSettings }}</template>
<template #caption>
{{ i18n.ts._customEmojisManager._gridCommon.searchSettingCaption }}
</template>
<div class="_gaps">
<div :class="[[spMode ? $style.searchAreaSp : $style.searchArea]]">
<MkInput
v-model="queryName"
:debounce="true"
type="search"
autocapitalize="off"
class="col1 row1"
@enter="onSearchRequest"
>
<template #label>name</template>
</MkInput>
<MkInput
v-model="queryCategory"
:debounce="true"
type="search"
autocapitalize="off"
class="col2 row1"
@enter="onSearchRequest"
>
<template #label>category</template>
</MkInput>
<MkInput
v-model="queryAlias"
:debounce="true"
type="search"
autocapitalize="off"
class="col3 row1"
@enter="onSearchRequest"
>
<template #label>alias</template>
</MkInput>
<MkInput
v-model="queryType"
:debounce="true"
type="search"
autocapitalize="off"
class="col1 row2"
@enter="onSearchRequest"
>
<template #label>type</template>
</MkInput>
<MkInput
v-model="queryLicense"
:debounce="true"
type="search"
autocapitalize="off"
class="col2 row2"
@enter="onSearchRequest"
>
<template #label>license</template>
</MkInput>
<MkSelect
v-model="querySensitive"
class="col3 row2"
>
<template #label>sensitive</template>
<option :value="null">-</option>
<option :value="true">true</option>
<option :value="false">false</option>
</MkSelect>
<MkSelect
v-model="queryLocalOnly"
class="col1 row3"
>
<template #label>localOnly</template>
<option :value="null">-</option>
<option :value="true">true</option>
<option :value="false">false</option>
</MkSelect>
<MkInput
v-model="queryUpdatedAtFrom"
:debounce="true"
type="date"
autocapitalize="off"
class="col2 row3"
@enter="onSearchRequest"
>
<template #label>updatedAt(from)</template>
</MkInput>
<MkInput
v-model="queryUpdatedAtTo"
:debounce="true"
type="date"
autocapitalize="off"
class="col3 row3"
@enter="onSearchRequest"
>
<template #label>updatedAt(to)</template>
</MkInput>
<MkInput
v-model="queryRolesText"
:debounce="true"
type="text"
readonly
autocapitalize="off"
class="col1 row4"
@click="onQueryRolesEditClicked"
>
<template #label>role</template>
<template #suffix><span class="ti ti-pencil"/></template>
</MkInput>
</div>
<XSortOrderFolder :sortOrders="sortOrders" @update="onSortOrderUpdate"/>
<div :class="[[spMode ? $style.searchButtonsSp : $style.searchButtons]]">
<MkButton primary @click="onSearchRequest">
{{ i18n.ts.search }}
</MkButton>
<MkButton @click="onQueryResetButtonClicked">
{{ i18n.ts.reset }}
</MkButton>
</div>
</div>
</MkFolder>
<XRegisterLogsFolder :logs="requestLogs"/>
<div :class="$style.gridArea"> <div :class="$style.gridArea">
<MkGrid :data="gridItems" :settings="setupGrid()" @event="onGridEvent"/> <MkGrid :data="gridItems" :settings="setupGrid()" @event="onGridEvent"/>
</div> </div>
@ -155,7 +147,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton @click="onGridResetButtonClicked">{{ i18n.ts.reset }}</MkButton> <MkButton @click="onGridResetButtonClicked">{{ i18n.ts.reset }}</MkButton>
</div> </div>
</div> </div>
</div> </template>
</div> </div>
</template> </template>
@ -360,7 +352,7 @@ const currentPage = ref<number>(0);
const queryName = ref<string | null>(null); const queryName = ref<string | null>(null);
const queryCategory = ref<string | null>(null); const queryCategory = ref<string | null>(null);
const queryAlias = ref<string | null>(null); const queryAliases = ref<string | null>(null);
const queryType = ref<string | null>(null); const queryType = ref<string | null>(null);
const queryLicense = ref<string | null>(null); const queryLicense = ref<string | null>(null);
const queryUpdatedAtFrom = ref<string | null>(null); const queryUpdatedAtFrom = ref<string | null>(null);
@ -509,7 +501,7 @@ async function onSearchRequest() {
function onQueryResetButtonClicked() { function onQueryResetButtonClicked() {
queryName.value = null; queryName.value = null;
queryCategory.value = null; queryCategory.value = null;
queryAlias.value = null; queryAliases.value = null;
queryType.value = null; queryType.value = null;
queryLicense.value = null; queryLicense.value = null;
queryUpdatedAtFrom.value = null; queryUpdatedAtFrom.value = null;
@ -552,7 +544,7 @@ async function refreshCustomEmojis() {
const query: Misskey.entities.AdminEmojiV2ListRequest['query'] = { const query: Misskey.entities.AdminEmojiV2ListRequest['query'] = {
name: emptyStrToUndefined(queryName.value), name: emptyStrToUndefined(queryName.value),
type: emptyStrToUndefined(queryType.value), type: emptyStrToUndefined(queryType.value),
aliases: emptyStrToUndefined(queryAlias.value), aliases: emptyStrToUndefined(queryAliases.value),
category: emptyStrToUndefined(queryCategory.value), category: emptyStrToUndefined(queryCategory.value),
license: emptyStrToUndefined(queryLicense.value), license: emptyStrToUndefined(queryLicense.value),
isSensitive: querySensitive.value ? Boolean(querySensitive.value).valueOf() : undefined, isSensitive: querySensitive.value ? Boolean(querySensitive.value).valueOf() : undefined,

View File

@ -17,7 +17,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="[[spMode ? $style.searchAreaSp : $style.searchArea]]"> <div :class="[[spMode ? $style.searchAreaSp : $style.searchArea]]">
<MkInput <MkInput
v-model="queryName" v-model="queryName"
:debounce="true"
type="search" type="search"
autocapitalize="off" autocapitalize="off"
class="col1 row1" class="col1 row1"
@ -27,7 +26,6 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput> </MkInput>
<MkInput <MkInput
v-model="queryHost" v-model="queryHost"
:debounce="true"
type="search" type="search"
autocapitalize="off" autocapitalize="off"
class="col2 row1" class="col2 row1"
@ -37,7 +35,6 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput> </MkInput>
<MkInput <MkInput
v-model="queryUri" v-model="queryUri"
:debounce="true"
type="search" type="search"
autocapitalize="off" autocapitalize="off"
class="col1 row2" class="col1 row2"
@ -47,7 +44,6 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput> </MkInput>
<MkInput <MkInput
v-model="queryPublicUrl" v-model="queryPublicUrl"
:debounce="true"
type="search" type="search"
autocapitalize="off" autocapitalize="off"
class="col2 row2" class="col2 row2"