From d392edbc6b75f1793412340389957248dc6a1cdc Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sat, 21 Oct 2023 22:03:19 +0200 Subject: [PATCH] test: more search options --- packages/backend/src/core/SearchService.ts | 8 +++++++- .../src/server/api/endpoints/notes/search.ts | 4 ++++ packages/frontend/src/pages/search.note.vue | 13 +++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/core/SearchService.ts b/packages/backend/src/core/SearchService.ts index b6d2bcabc..f410891ff 100644 --- a/packages/backend/src/core/SearchService.ts +++ b/packages/backend/src/core/SearchService.ts @@ -29,6 +29,7 @@ type Q = { op: 'is not null', k: K} | { op: 'and', qs: Q[] } | { op: 'or', qs: Q[] } | + { op: 'likefile', k: K, v: V } | { op: 'not', q: Q }; function compileValue(value: V): string { @@ -54,6 +55,7 @@ function compileQuery(q: Q): string { case 'or': return q.qs.length === 0 ? '' : `(${ q.qs.map(_q => compileQuery(_q)).join(' OR ') })`; case 'is null': return `(${q.k} IS NULL)`; case 'is not null': return `(${q.k} IS NOT NULL)`; + case 'likefile': return `(${q.k}::varchar LIKE ${compileValue(q.v)}))`; case 'not': return `(NOT ${compileQuery(q.q)})`; default: throw new Error('unrecognized query operator'); } @@ -93,6 +95,7 @@ export class SearchService { 'userHost', 'channelId', 'tags', + 'attachedFileTypes', ], typoTolerance: { enabled: false, @@ -158,6 +161,8 @@ export class SearchService { userId?: MiNote['userId'] | null; channelId?: MiNote['channelId'] | null; host?: string | null; + filetype?: string | null; + order?: string | null; }, pagination: { untilId?: MiNote['id']; sinceId?: MiNote['id']; @@ -172,6 +177,7 @@ export class SearchService { if (pagination.sinceId) filter.qs.push({ op: '>', k: 'createdAt', v: this.idService.parse(pagination.sinceId).date.getTime() }); if (opts.userId) filter.qs.push({ op: '=', k: 'userId', v: opts.userId }); if (opts.channelId) filter.qs.push({ op: '=', k: 'channelId', v: opts.channelId }); + if (opts.filetype) filter.qs.push({ op: 'likefile', k: 'attachedFileTypes', v: `%${opts.filetype}%` }); if (opts.host) { if (opts.host === '.') { filter.qs.push({ op: 'is null', k: 'userHost' }); @@ -180,7 +186,7 @@ export class SearchService { } } const res = await this.meilisearchNoteIndex!.search(q, { - sort: ['createdAt:desc'], + sort: [`createdAt:${opts.order}`], matchingStrategy: 'all', attributesToRetrieve: ['id', 'createdAt'], filter: compileQuery(filter), diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index 4425d4593..06efa3d95 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -46,8 +46,10 @@ export const paramDef = { type: 'string', description: 'The local host is represented with `.`.', }, + filetype: { type: 'string', nullable: true }, userId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, channelId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + order: { type: 'string' }, }, required: ['query'], } as const; @@ -71,6 +73,8 @@ export default class extends Endpoint { // eslint- userId: ps.userId, channelId: ps.channelId, host: ps.host, + filetype: ps.filetype, + order: ps.order, }, { untilId: ps.untilId, sinceId: ps.sinceId, diff --git a/packages/frontend/src/pages/search.note.vue b/packages/frontend/src/pages/search.note.vue index 22fcb7c24..deaa6cfb5 100644 --- a/packages/frontend/src/pages/search.note.vue +++ b/packages/frontend/src/pages/search.note.vue @@ -14,6 +14,14 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.localOnly }} + Sort by newest to oldest + + + + + + + @@ -48,6 +56,7 @@ import MkInput from '@/components/MkInput.vue'; import MkRadios from '@/components/MkRadios.vue'; import MkButton from '@/components/MkButton.vue'; import MkSwitch from '@/components/MkSwitch.vue'; +import MkSelect from '@/components/MkSelect.vue'; import { i18n } from '@/i18n.js'; import * as os from '@/os.js'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; @@ -65,6 +74,8 @@ let searchOrigin = $ref('combined'); let notePagination = $ref(); let user = $ref(null); let isLocalOnly = $ref(false); +let order = $ref(false); +let filetype = $ref(null); function selectUser() { os.selectUser().then(_user => { @@ -101,6 +112,8 @@ async function search() { params: { query: searchQuery, userId: user ? user.id : null, + order: !order ? 'desc' : 'asc', + filetype: filetype, }, };