[backend] Add in:bookmarks and in:favorites postgres FTS filters
This commit is contained in:
parent
8c43c5cae6
commit
855409332b
3 changed files with 45 additions and 7 deletions
|
@ -1487,6 +1487,7 @@ _filters:
|
||||||
title: "Advanced search filters"
|
title: "Advanced search filters"
|
||||||
learnMore: "View advanced filters"
|
learnMore: "View advanced filters"
|
||||||
wordFilters: "Filter by post text"
|
wordFilters: "Filter by post text"
|
||||||
|
inFilters: "Filter by bookmark and/or favorite status"
|
||||||
miscFilters: "Filter by following relationship and/or note type"
|
miscFilters: "Filter by following relationship and/or note type"
|
||||||
userDomain: "Filter by author, mentioned users, reply user or instance domain"
|
userDomain: "Filter by author, mentioned users, reply user or instance domain"
|
||||||
postDate: "Filter by post date"
|
postDate: "Filter by post date"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Brackets, SelectQueryBuilder, WhereExpressionBuilder } from "typeorm";
|
import { Brackets, SelectQueryBuilder, WhereExpressionBuilder } from "typeorm";
|
||||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||||
import { sqlRegexEscape } from "@/misc/sql-regex-escape.js";
|
import { sqlRegexEscape } from "@/misc/sql-regex-escape.js";
|
||||||
import { Followings, Users } from "@/models/index.js";
|
import { Followings, NoteFavorites, NoteReactions, Users } from "@/models/index.js";
|
||||||
|
|
||||||
const filters = {
|
const filters = {
|
||||||
"from": fromFilter,
|
"from": fromFilter,
|
||||||
|
@ -24,11 +24,11 @@ const filters = {
|
||||||
"-host": instanceFilterInverse,
|
"-host": instanceFilterInverse,
|
||||||
"filter": miscFilter,
|
"filter": miscFilter,
|
||||||
"-filter": miscFilterInverse,
|
"-filter": miscFilterInverse,
|
||||||
|
"in": inFilter,
|
||||||
|
"-in": inFilterInverse,
|
||||||
"has": attachmentFilter,
|
"has": attachmentFilter,
|
||||||
} as Record<string, (query: SelectQueryBuilder<any>, search: string, id: number) => any>
|
} as Record<string, (query: SelectQueryBuilder<any>, search: string, id: number) => any>
|
||||||
|
|
||||||
//TODO: editing the query should be possible, clicking search again resets it (it should be a twitter-like top of the page kind of deal)
|
|
||||||
|
|
||||||
export function generateFtsQuery(query: SelectQueryBuilder<any>, q: string): void {
|
export function generateFtsQuery(query: SelectQueryBuilder<any>, q: string): void {
|
||||||
const components = q.trim().split(" ");
|
const components = q.trim().split(" ");
|
||||||
const terms: string[] = [];
|
const terms: string[] = [];
|
||||||
|
@ -156,11 +156,11 @@ function miscFilter(query: SelectQueryBuilder<any>, filter: string) {
|
||||||
if (filter === 'followers') {
|
if (filter === 'followers') {
|
||||||
subQuery = Followings.createQueryBuilder('following')
|
subQuery = Followings.createQueryBuilder('following')
|
||||||
.select('following.followerId')
|
.select('following.followerId')
|
||||||
.where('following.followeeId = :meId')
|
.where('following.followeeId = :meId');
|
||||||
} else if (filter === 'following') {
|
} else if (filter === 'following') {
|
||||||
subQuery = Followings.createQueryBuilder('following')
|
subQuery = Followings.createQueryBuilder('following')
|
||||||
.select('following.followeeId')
|
.select('following.followeeId')
|
||||||
.where('following.followerId = :meId')
|
.where('following.followerId = :meId');
|
||||||
} else if (filter === 'replies' || filter === 'reply') {
|
} else if (filter === 'replies' || filter === 'reply') {
|
||||||
query.andWhere('note.replyId IS NOT NULL');
|
query.andWhere('note.replyId IS NOT NULL');
|
||||||
} else if (filter === 'boosts' || filter === 'boost' || filter === 'renotes' || filter === 'renote') {
|
} else if (filter === 'boosts' || filter === 'boost' || filter === 'renotes' || filter === 'renote') {
|
||||||
|
@ -175,11 +175,11 @@ function miscFilterInverse(query: SelectQueryBuilder<any>, filter: string) {
|
||||||
if (filter === 'followers') {
|
if (filter === 'followers') {
|
||||||
subQuery = Followings.createQueryBuilder('following')
|
subQuery = Followings.createQueryBuilder('following')
|
||||||
.select('following.followerId')
|
.select('following.followerId')
|
||||||
.where('following.followeeId = :meId')
|
.where('following.followeeId = :meId');
|
||||||
} else if (filter === 'following') {
|
} else if (filter === 'following') {
|
||||||
subQuery = Followings.createQueryBuilder('following')
|
subQuery = Followings.createQueryBuilder('following')
|
||||||
.select('following.followeeId')
|
.select('following.followeeId')
|
||||||
.where('following.followerId = :meId')
|
.where('following.followerId = :meId');
|
||||||
} else if (filter === 'replies' || filter === 'reply') {
|
} else if (filter === 'replies' || filter === 'reply') {
|
||||||
query.andWhere('note.replyId IS NULL');
|
query.andWhere('note.replyId IS NULL');
|
||||||
} else if (filter === 'boosts' || filter === 'boost' || filter === 'renotes' || filter === 'renote') {
|
} else if (filter === 'boosts' || filter === 'boost' || filter === 'renotes' || filter === 'renote') {
|
||||||
|
@ -189,6 +189,36 @@ function miscFilterInverse(query: SelectQueryBuilder<any>, filter: string) {
|
||||||
if (subQuery !== null) query.andWhere(`note.userId NOT IN (${subQuery.getQuery()})`);
|
if (subQuery !== null) query.andWhere(`note.userId NOT IN (${subQuery.getQuery()})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inFilter(query: SelectQueryBuilder<any>, filter: string) {
|
||||||
|
let subQuery: SelectQueryBuilder<any> | null = null;
|
||||||
|
if (filter === 'bookmarks') {
|
||||||
|
subQuery = NoteFavorites.createQueryBuilder('bookmark')
|
||||||
|
.select('bookmark.noteId')
|
||||||
|
.where('bookmark.userId = :meId');
|
||||||
|
} else if (filter === 'favorites' || filter === 'favourites' || filter === 'reactions' || filter === 'likes') {
|
||||||
|
subQuery = NoteReactions.createQueryBuilder('react')
|
||||||
|
.select('react.noteId')
|
||||||
|
.where('react.userId = :meId');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subQuery !== null) query.andWhere(`note.id IN (${subQuery.getQuery()})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inFilterInverse(query: SelectQueryBuilder<any>, filter: string) {
|
||||||
|
let subQuery: SelectQueryBuilder<any> | null = null;
|
||||||
|
if (filter === 'bookmarks') {
|
||||||
|
subQuery = NoteFavorites.createQueryBuilder('bookmark')
|
||||||
|
.select('bookmark.noteId')
|
||||||
|
.where('bookmark.userId = :meId');
|
||||||
|
} else if (filter === 'favorites' || filter === 'favourites' || filter === 'reactions' || filter === 'likes') {
|
||||||
|
subQuery = NoteReactions.createQueryBuilder('react')
|
||||||
|
.select('react.noteId')
|
||||||
|
.where('react.userId = :meId');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subQuery !== null) query.andWhere(`note.id NOT IN (${subQuery.getQuery()})`);
|
||||||
|
}
|
||||||
|
|
||||||
function attachmentFilter(query: SelectQueryBuilder<any>, filter: string) {
|
function attachmentFilter(query: SelectQueryBuilder<any>, filter: string) {
|
||||||
switch(filter) {
|
switch(filter) {
|
||||||
case 'image':
|
case 'image':
|
||||||
|
|
|
@ -34,6 +34,12 @@
|
||||||
<p><code>[-]instance:local|domain.tld</code></p>
|
<p><code>[-]instance:local|domain.tld</code></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="section _block">
|
||||||
|
<div class="title">{{ i18n.ts._filters._dialog.inFilters }}</div>
|
||||||
|
<div class="content">
|
||||||
|
<p><code>[-]in:bookmarks|favorites</code></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="section _block">
|
<div class="section _block">
|
||||||
<div class="title">{{ i18n.ts._filters._dialog.miscFilters }}</div>
|
<div class="title">{{ i18n.ts._filters._dialog.miscFilters }}</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@ -59,6 +65,7 @@
|
||||||
<div class="title">{{ i18n.ts._filters._dialog.infoEnd }}</div>
|
<div class="title">{{ i18n.ts._filters._dialog.infoEnd }}</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>{{ i18n.ts._filters._dialog.infoEnd1 }}</p>
|
<p>{{ i18n.ts._filters._dialog.infoEnd1 }}</p>
|
||||||
|
<p><code>in:likes = in:reactions = in:favourites = in:favorites</code></p>
|
||||||
<p><code>filter:reply = filter:replies</code></p>
|
<p><code>filter:reply = filter:replies</code></p>
|
||||||
<p><code>search:word[s] = match:word[s]</code></p>
|
<p><code>search:word[s] = match:word[s]</code></p>
|
||||||
<p><code>domain: = host: = instance:</code></p>
|
<p><code>domain: = host: = instance:</code></p>
|
||||||
|
|
Loading…
Reference in a new issue