discourse: save superfluous query of `likes` table (#1302)
Summary: When inserting a “like” action with `INSERT OR IGNORE` semantics, we also learn whether the action had any effect. We can use this bit to avoid a separate query checking whether the “like” already exists. As mentioned here: <https://github.com/sourcecred/sourcecred/pull/1298#discussion_r314994911> Test Plan: Running `yarn test` passes as is, and fails if you change `addLike` to always return either `changed: true` or `changed: false`. wchargin-branch: discourse-likes-one-query
This commit is contained in:
parent
5e26424d82
commit
9fc1482d9d
|
@ -391,39 +391,49 @@ export class Mirror implements DiscourseData {
|
||||||
// who we either haven't scanned in the last week, or who have been active
|
// who we either haven't scanned in the last week, or who have been active
|
||||||
// since our last scan. This would likely improve the performance of this
|
// since our last scan. This would likely improve the performance of this
|
||||||
// section of the update significantly.
|
// section of the update significantly.
|
||||||
const insertLike = db.prepare(
|
|
||||||
|
/**
|
||||||
|
* Add a like action to the database. The user of the like is
|
||||||
|
* assumed to already exist in the database; if this is not known to
|
||||||
|
* be the case, run `addUser(like.username)` first.
|
||||||
|
*
|
||||||
|
* Returns a status indicating whether the database changed as a
|
||||||
|
* result of this call.
|
||||||
|
*/
|
||||||
|
const addLike: (like: LikeAction) => {|+changed: boolean|} = (() => {
|
||||||
|
const query = db.prepare(
|
||||||
dedent`\
|
dedent`\
|
||||||
INSERT INTO likes (
|
INSERT OR IGNORE INTO likes (
|
||||||
post_id, timestamp_ms, username
|
post_id,
|
||||||
|
timestamp_ms,
|
||||||
|
username
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:post_id, :timestamp_ms, :username
|
:post_id,
|
||||||
|
:timestamp_ms,
|
||||||
|
:username
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
const alreadySeenLike = db
|
return function addLike(like: LikeAction) {
|
||||||
.prepare(
|
const runResult = query.run({
|
||||||
dedent`\
|
post_id: like.postId,
|
||||||
SELECT * FROM likes
|
timestamp_ms: like.timestampMs,
|
||||||
WHERE post_id = :post_id AND username = :username
|
username: like.username,
|
||||||
`
|
});
|
||||||
)
|
return {changed: runResult.changes > 0};
|
||||||
.pluck();
|
};
|
||||||
|
})();
|
||||||
for (const user of this.users()) {
|
for (const user of this.users()) {
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
let upToDate = false;
|
let upToDate = false;
|
||||||
while (!upToDate) {
|
while (!upToDate) {
|
||||||
const likeActions = await this._fetcher.likesByUser(user, offset);
|
const likeActions = await this._fetcher.likesByUser(user, offset);
|
||||||
possiblePageSize = Math.max(likeActions.length, possiblePageSize);
|
possiblePageSize = Math.max(likeActions.length, possiblePageSize);
|
||||||
for (const {timestampMs, postId, username} of likeActions) {
|
for (const like of likeActions) {
|
||||||
if (alreadySeenLike.get({post_id: postId, username: username})) {
|
if (!addLike(like).changed) {
|
||||||
upToDate = true;
|
upToDate = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
insertLike.run({
|
|
||||||
post_id: postId,
|
|
||||||
timestamp_ms: timestampMs,
|
|
||||||
username: username,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (likeActions.length === 0 || likeActions.length < possiblePageSize) {
|
if (likeActions.length === 0 || likeActions.length < possiblePageSize) {
|
||||||
upToDate = true;
|
upToDate = true;
|
||||||
|
|
Loading…
Reference in New Issue