merge: Additional performance fixes (!1095)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1095 Approved-by: dakkar <dakkar@thenautilus.net> Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
commit
20a2505543
21 changed files with 396 additions and 282 deletions
|
|
@ -7,6 +7,7 @@ import { DI } from '@/di-symbols.js';
|
|||
import type { LatestNotesRepository, NotesRepository } from '@/models/_.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import Logger from '@/logger.js';
|
||||
import { QueryService } from './QueryService.js';
|
||||
|
||||
@Injectable()
|
||||
export class LatestNoteService {
|
||||
|
|
@ -14,11 +15,12 @@ export class LatestNoteService {
|
|||
|
||||
constructor(
|
||||
@Inject(DI.notesRepository)
|
||||
private notesRepository: NotesRepository,
|
||||
private readonly notesRepository: NotesRepository,
|
||||
|
||||
@Inject(DI.latestNotesRepository)
|
||||
private latestNotesRepository: LatestNotesRepository,
|
||||
private readonly latestNotesRepository: LatestNotesRepository,
|
||||
|
||||
private readonly queryService: QueryService,
|
||||
loggerService: LoggerService,
|
||||
) {
|
||||
this.logger = loggerService.getLogger('LatestNoteService');
|
||||
|
|
@ -91,7 +93,7 @@ export class LatestNoteService {
|
|||
|
||||
// Find the newest remaining note for the user.
|
||||
// We exclude DMs and pure renotes.
|
||||
const nextLatest = await this.notesRepository
|
||||
const query = this.notesRepository
|
||||
.createQueryBuilder('note')
|
||||
.select()
|
||||
.where({
|
||||
|
|
@ -106,18 +108,11 @@ export class LatestNoteService {
|
|||
? Not(null)
|
||||
: null,
|
||||
})
|
||||
.andWhere(`
|
||||
(
|
||||
note."renoteId" IS NULL
|
||||
OR note.text IS NOT NULL
|
||||
OR note.cw IS NOT NULL
|
||||
OR note."replyId" IS NOT NULL
|
||||
OR note."hasPoll"
|
||||
OR note."fileIds" != '{}'
|
||||
)
|
||||
`)
|
||||
.orderBy({ id: 'DESC' })
|
||||
.getOne();
|
||||
.orderBy({ id: 'DESC' });
|
||||
|
||||
this.queryService.andIsNotRenote(query, 'note');
|
||||
|
||||
const nextLatest = await query.getOne();
|
||||
if (!nextLatest) return;
|
||||
|
||||
// Record it as the latest
|
||||
|
|
|
|||
|
|
@ -160,15 +160,15 @@ export class QueryService {
|
|||
// Reply to me
|
||||
.orWhere(':meId = note.replyUserId')
|
||||
// DM to me
|
||||
.orWhere(':meId = ANY (note.visibleUserIds)')
|
||||
.orWhere(':meIdAsList <@ note.visibleUserIds')
|
||||
// Mentions me
|
||||
.orWhere(':meId = ANY (note.mentions)')
|
||||
.orWhere(':meIdAsList <@ note.mentions')
|
||||
// Followers-only post
|
||||
.orWhere(new Brackets(qb => this
|
||||
.andFollowingUser(qb, ':meId', 'note.userId')
|
||||
.andWhere('note.visibility = \'followers\'')));
|
||||
|
||||
q.setParameters({ meId: me.id });
|
||||
q.setParameters({ meId: me.id, meIdAsList: [me.id] });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
@ -188,15 +188,8 @@ export class QueryService {
|
|||
}
|
||||
|
||||
@bindThis
|
||||
public generateExcludedRenotesQueryForNotes<E extends ObjectLiteral>(q: SelectQueryBuilder<E>): SelectQueryBuilder<E> {
|
||||
return q
|
||||
.andWhere(new Brackets(qb => qb
|
||||
.orWhere('note.renoteId IS NULL')
|
||||
.orWhere('note.text IS NOT NULL')
|
||||
.orWhere('note.cw IS NOT NULL')
|
||||
.orWhere('note.replyId IS NOT NULL')
|
||||
.orWhere('note.hasPoll = true')
|
||||
.orWhere('note.fileIds != \'{}\'')));
|
||||
public generateExcludedRenotesQueryForNotes<Q extends WhereExpressionBuilder>(q: Q): Q {
|
||||
return this.andIsNotRenote(q, 'note');
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -256,6 +249,120 @@ export class QueryService {
|
|||
return q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds OR condition that noteProp (note ID) refers to a quote.
|
||||
* The prop should be an expression, not a raw value.
|
||||
*/
|
||||
@bindThis
|
||||
public orIsQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||
return this.addIsQuote(q, noteProp, 'orWhere');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds AND condition that noteProp (note ID) refers to a quote.
|
||||
* The prop should be an expression, not a raw value.
|
||||
*/
|
||||
@bindThis
|
||||
public andIsQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||
return this.addIsQuote(q, noteProp, 'andWhere');
|
||||
}
|
||||
|
||||
private addIsQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||
return q[join](new Brackets(qb => qb
|
||||
.andWhere(`${noteProp}.renoteId IS NOT NULL`)
|
||||
.andWhere(new Brackets(qbb => qbb
|
||||
.orWhere(`${noteProp}.text IS NOT NULL`)
|
||||
.orWhere(`${noteProp}.cw IS NOT NULL`)
|
||||
.orWhere(`${noteProp}.replyId IS NOT NULL`)
|
||||
.orWhere(`${noteProp}.hasPoll = true`)
|
||||
.orWhere(`${noteProp}.fileIds != '{}'`)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds OR condition that noteProp (note ID) does not refer to a quote.
|
||||
* The prop should be an expression, not a raw value.
|
||||
*/
|
||||
@bindThis
|
||||
public orIsNotQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||
return this.addIsNotQuote(q, noteProp, 'orWhere');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds AND condition that noteProp (note ID) does not refer to a quote.
|
||||
* The prop should be an expression, not a raw value.
|
||||
*/
|
||||
@bindThis
|
||||
public andIsNotQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||
return this.addIsNotQuote(q, noteProp, 'andWhere');
|
||||
}
|
||||
|
||||
private addIsNotQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||
return q[join](new Brackets(qb => qb
|
||||
.orWhere(`${noteProp}.renoteId IS NULL`)
|
||||
.orWhere(new Brackets(qb => qb
|
||||
.andWhere(`${noteProp}.text IS NULL`)
|
||||
.andWhere(`${noteProp}.cw IS NULL`)
|
||||
.andWhere(`${noteProp}.replyId IS NULL`)
|
||||
.andWhere(`${noteProp}.hasPoll = false`)
|
||||
.andWhere(`${noteProp}.fileIds = '{}'`)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds OR condition that noteProp (note ID) refers to a renote.
|
||||
* The prop should be an expression, not a raw value.
|
||||
*/
|
||||
@bindThis
|
||||
public orIsRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||
return this.addIsRenote(q, noteProp, 'orWhere');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds AND condition that noteProp (note ID) refers to a renote.
|
||||
* The prop should be an expression, not a raw value.
|
||||
*/
|
||||
@bindThis
|
||||
public andIsRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||
return this.addIsRenote(q, noteProp, 'andWhere');
|
||||
}
|
||||
|
||||
private addIsRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||
return q[join](new Brackets(qb => qb
|
||||
.andWhere(`${noteProp}.renoteId IS NOT NULL`)
|
||||
.andWhere(`${noteProp}.text IS NULL`)
|
||||
.andWhere(`${noteProp}.cw IS NULL`)
|
||||
.andWhere(`${noteProp}.replyId IS NULL`)
|
||||
.andWhere(`${noteProp}.hasPoll = false`)
|
||||
.andWhere(`${noteProp}.fileIds = '{}'`)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds OR condition that noteProp (note ID) does not refer to a renote.
|
||||
* The prop should be an expression, not a raw value.
|
||||
*/
|
||||
@bindThis
|
||||
public orIsNotRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||
return this.addIsNotRenote(q, noteProp, 'orWhere');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds AND condition that noteProp (note ID) does not refer to a renote.
|
||||
* The prop should be an expression, not a raw value.
|
||||
*/
|
||||
@bindThis
|
||||
public andIsNotRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||
return this.addIsNotRenote(q, noteProp, 'andWhere');
|
||||
}
|
||||
|
||||
private addIsNotRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||
return q[join](new Brackets(qb => qb
|
||||
.orWhere(`${noteProp}.renoteId IS NULL`)
|
||||
.orWhere(`${noteProp}.text IS NOT NULL`)
|
||||
.orWhere(`${noteProp}.cw IS NOT NULL`)
|
||||
.orWhere(`${noteProp}.replyId IS NOT NULL`)
|
||||
.orWhere(`${noteProp}.hasPoll = true`)
|
||||
.orWhere(`${noteProp}.fileIds != '{}'`)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds OR condition that followerProp (user ID) is following followeeProp (user ID).
|
||||
* Both props should be expressions, not raw values.
|
||||
|
|
@ -283,6 +390,33 @@ export class QueryService {
|
|||
return q[join](`EXISTS (${followingQuery.getQuery()})`, followingQuery.getParameters());
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds OR condition that followerProp (user ID) is following followeeProp (channel ID).
|
||||
* Both props should be expressions, not raw values.
|
||||
*/
|
||||
@bindThis
|
||||
public orFollowingChannel<Q extends WhereExpressionBuilder>(q: Q, followerProp: string, followeeProp: string): Q {
|
||||
return this.addFollowingChannel(q, followerProp, followeeProp, 'orWhere');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds AND condition that followerProp (user ID) is following followeeProp (channel ID).
|
||||
* Both props should be expressions, not raw values.
|
||||
*/
|
||||
@bindThis
|
||||
public andFollowingChannel<Q extends WhereExpressionBuilder>(q: Q, followerProp: string, followeeProp: string): Q {
|
||||
return this.addFollowingChannel(q, followerProp, followeeProp, 'andWhere');
|
||||
}
|
||||
|
||||
private addFollowingChannel<Q extends WhereExpressionBuilder>(q: Q, followerProp: string, followeeProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||
const followingQuery = this.channelFollowingsRepository.createQueryBuilder('following')
|
||||
.select('1')
|
||||
.andWhere(`following.followerId = ${followerProp}`)
|
||||
.andWhere(`following.followeeId = ${followeeProp}`);
|
||||
|
||||
return q[join](`EXISTS (${followingQuery.getQuery()})`, followingQuery.getParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds OR condition that blockerProp (user ID) is not blocking blockeeProp (user ID).
|
||||
* Both props should be expressions, not raw values.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue