enhance(backend): ANY()をやめる (MisskeyIO#239)

This commit is contained in:
まっちゃとーにゅ 2023-11-20 13:15:09 +09:00 committed by GitHub
parent f4d9269eec
commit 24d2f2aa3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 12 additions and 10 deletions

View file

@ -212,8 +212,8 @@ export class QueryService {
// または 自分自身 // または 自分自身
.orWhere('note.userId = :meId') .orWhere('note.userId = :meId')
// または 自分宛て // または 自分宛て
.orWhere(':meId = ANY(note.visibleUserIds)') .orWhere(':meIdAsList <@ note.visibleUserIds')
.orWhere(':meId = ANY(note.mentions)') .orWhere(':meIdAsList <@ note.mentions')
.orWhere(new Brackets(qb => { .orWhere(new Brackets(qb => {
qb qb
// または フォロワー宛ての投稿であり、 // または フォロワー宛ての投稿であり、
@ -228,7 +228,7 @@ export class QueryService {
})); }));
})); }));
q.setParameters({ meId: me.id }); q.setParameters({ meId: me.id, meIdAsList: [me.id] });
} }
} }

View file

@ -74,7 +74,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} }
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId); const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId);
query.andWhere(':file = ANY(note.fileIds)', { file: file.id }); query.andWhere(':file <@ note.fileIds', { file: [file.id] });
const notes = await query.limit(ps.limit).getMany(); const notes = await query.limit(ps.limit).getMany();

View file

@ -6,6 +6,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository } from '@/models/_.js'; import type { UsersRepository } from '@/models/_.js';
import { safeForSql } from "@/misc/safe-for-sql.js";
import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -47,8 +48,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private userEntityService: UserEntityService, private userEntityService: UserEntityService,
) { ) {
super(meta, paramDef, async (ps, me) => { super(meta, paramDef, async (ps, me) => {
if (!safeForSql(normalizeForSearch(ps.tag))) throw new Error('Injection');
const query = this.usersRepository.createQueryBuilder('user') const query = this.usersRepository.createQueryBuilder('user')
.where(':tag = ANY(user.tags)', { tag: normalizeForSearch(ps.tag) }) .where(':tag <@ user.tags', { tag: [normalizeForSearch(ps.tag)] })
.andWhere('user.isSuspended = FALSE'); .andWhere('user.isSuspended = FALSE');
const recent = new Date(Date.now() - (1000 * 60 * 60 * 24 * 5)); const recent = new Date(Date.now() - (1000 * 60 * 60 * 24 * 5));

View file

@ -60,9 +60,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId) const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
.andWhere(new Brackets(qb => { .andWhere(new Brackets(qb => {
qb qb // このmeIdAsListパラメータはqueryServiceのgenerateVisibilityQueryでセットされる
.where(`'{"${me.id}"}' <@ note.mentions`) .where(':meIdAsList <@ note.mentions')
.orWhere(`'{"${me.id}"}' <@ note.visibleUserIds`); .orWhere(':meIdAsList <@ note.visibleUserIds');
})) }))
// Avoid scanning primary key index // Avoid scanning primary key index
.orderBy('CONCAT(note.id)', 'DESC') .orderBy('CONCAT(note.id)', 'DESC')

View file

@ -87,14 +87,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
try { try {
if (ps.tag) { if (ps.tag) {
if (!safeForSql(normalizeForSearch(ps.tag))) throw new Error('Injection'); if (!safeForSql(normalizeForSearch(ps.tag))) throw new Error('Injection');
query.andWhere(`'{"${normalizeForSearch(ps.tag)}"}' <@ note.tags`); query.andWhere(':tag <@ note.tags', { tag: [normalizeForSearch(ps.tag)] });
} else { } else {
query.andWhere(new Brackets(qb => { query.andWhere(new Brackets(qb => {
for (const tags of ps.query!) { for (const tags of ps.query!) {
qb.orWhere(new Brackets(qb => { qb.orWhere(new Brackets(qb => {
for (const tag of tags) { for (const tag of tags) {
if (!safeForSql(normalizeForSearch(tag))) throw new Error('Injection'); if (!safeForSql(normalizeForSearch(tag))) throw new Error('Injection');
qb.andWhere(`'{"${normalizeForSearch(tag)}"}' <@ note.tags`); qb.andWhere(':tag <@ note.tags', { tag: [normalizeForSearch(tag)] });
} }
})); }));
} }