Discourse: adds bumpedMsForTopic and topicsInCategories queries (#1458)
bumpedMsForTopic For the given topic ID, retrieves the bumpedMs value. Returns null, when the topic wasn't found. Used by the new update code as a fallback value when making API calls that don't contain the bumpedMs field. topicsInCategories Finds the TopicIds of topics that have one of the categoryIds as it's category. Useful to find out which topics a set of categories contains. For example to implement the `recheckTopicsInCategories` mirror option, or to locate topics for the initiative plugin.
This commit is contained in:
parent
564fd89b1e
commit
7deb0a3205
|
@ -75,6 +75,11 @@ describe("plugins/discourse/createGraph", () => {
|
|||
maxTopicId: this._topics.reduce((max, t) => Math.max(t.id, max), 0),
|
||||
};
|
||||
}
|
||||
topicsInCategories() {
|
||||
throw new Error(
|
||||
"Method topicsInCategories should be unused for createGraph"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function example() {
|
||||
|
|
|
@ -3,7 +3,14 @@
|
|||
import type {Database} from "better-sqlite3";
|
||||
import stringify from "json-stable-stringify";
|
||||
import dedent from "../../util/dedent";
|
||||
import type {TopicId, PostId, Topic, Post, LikeAction} from "./fetch";
|
||||
import type {
|
||||
CategoryId,
|
||||
TopicId,
|
||||
PostId,
|
||||
Topic,
|
||||
Post,
|
||||
LikeAction,
|
||||
} from "./fetch";
|
||||
|
||||
// The version should be bumped any time the database schema is changed,
|
||||
// so that the cache will be properly invalidated.
|
||||
|
@ -45,6 +52,13 @@ export interface ReadRepository {
|
|||
* Gets all of the like actions in the history.
|
||||
*/
|
||||
likes(): $ReadOnlyArray<LikeAction>;
|
||||
|
||||
/**
|
||||
* Finds the TopicIds of topics that have one of the categoryIds as it's category.
|
||||
*/
|
||||
topicsInCategories(
|
||||
categoryIds: $ReadOnlyArray<CategoryId>
|
||||
): $ReadOnlyArray<TopicId>;
|
||||
}
|
||||
|
||||
export type MaxIds = {|
|
||||
|
@ -63,6 +77,12 @@ export interface MirrorRepository extends ReadRepository {
|
|||
addTopic(topic: Topic): AddResult;
|
||||
addPost(post: Post): AddResult;
|
||||
addLike(like: LikeAction): AddResult;
|
||||
|
||||
/**
|
||||
* For the given topic ID, retrieves the bumpedMs value.
|
||||
* Returns null, when the topic wasn't found.
|
||||
*/
|
||||
bumpedMsForTopic(id: TopicId): number | null;
|
||||
}
|
||||
|
||||
function toAddResult({
|
||||
|
@ -293,6 +313,27 @@ export class SqliteMirrorRepository
|
|||
return toAddResult(res);
|
||||
}
|
||||
|
||||
topicsInCategories(
|
||||
categoryIds: $ReadOnlyArray<CategoryId>
|
||||
): $ReadOnlyArray<TopicId> {
|
||||
return this._db
|
||||
.prepare(
|
||||
dedent`\
|
||||
SELECT id FROM topics
|
||||
WHERE category_id IN (${categoryIds.map((_) => "?").join(",")})
|
||||
`
|
||||
)
|
||||
.all(...categoryIds)
|
||||
.map((t) => t.id);
|
||||
}
|
||||
|
||||
bumpedMsForTopic(id: TopicId): number | null {
|
||||
const res = this._db
|
||||
.prepare(`SELECT bumped_ms FROM topics WHERE id = :id`)
|
||||
.get({id});
|
||||
return res != null ? res.bumped_ms : null;
|
||||
}
|
||||
|
||||
addPost(post: Post): AddResult {
|
||||
this.addUser(post.authorUsername);
|
||||
const res = this._db
|
||||
|
|
|
@ -4,6 +4,7 @@ import Database from "better-sqlite3";
|
|||
import fs from "fs";
|
||||
import tmp from "tmp";
|
||||
import {SqliteMirrorRepository} from "./mirrorRepository";
|
||||
import type {Topic} from "./fetch";
|
||||
|
||||
describe("plugins/discourse/mirrorRepository", () => {
|
||||
it("rejects a different server url without changing the database", () => {
|
||||
|
@ -24,4 +25,117 @@ describe("plugins/discourse/mirrorRepository", () => {
|
|||
expect(() => new SqliteMirrorRepository(db, url1)).not.toThrow();
|
||||
expect(fs.readFileSync(filename).toJSON()).toEqual(data);
|
||||
});
|
||||
|
||||
it("bumpedMsForTopic finds an existing topic's bumpedMs", () => {
|
||||
// Given
|
||||
const db = new Database(":memory:");
|
||||
const url = "http://example.com";
|
||||
const repository = new SqliteMirrorRepository(db, url);
|
||||
const topic: Topic = {
|
||||
id: 123,
|
||||
categoryId: 1,
|
||||
title: "Sample topic",
|
||||
timestampMs: 456789,
|
||||
bumpedMs: 456999,
|
||||
authorUsername: "credbot",
|
||||
};
|
||||
|
||||
// When
|
||||
repository.addTopic(topic);
|
||||
const bumpedMs = repository.bumpedMsForTopic(topic.id);
|
||||
|
||||
// Then
|
||||
expect(bumpedMs).toEqual(topic.bumpedMs);
|
||||
});
|
||||
|
||||
it("bumpedMsForTopic returns null when missing topic", () => {
|
||||
// Given
|
||||
const db = new Database(":memory:");
|
||||
const url = "http://example.com";
|
||||
const repository = new SqliteMirrorRepository(db, url);
|
||||
|
||||
// When
|
||||
const bumpedMs = repository.bumpedMsForTopic(123);
|
||||
|
||||
// Then
|
||||
expect(bumpedMs).toEqual(null);
|
||||
});
|
||||
|
||||
it("topicsInCategories finds an an existing topic by categoryId", () => {
|
||||
// Given
|
||||
const db = new Database(":memory:");
|
||||
const url = "http://example.com";
|
||||
const repository = new SqliteMirrorRepository(db, url);
|
||||
const topic: Topic = {
|
||||
id: 123,
|
||||
categoryId: 42,
|
||||
title: "Sample topic",
|
||||
timestampMs: 456789,
|
||||
bumpedMs: 456999,
|
||||
authorUsername: "credbot",
|
||||
};
|
||||
|
||||
// When
|
||||
repository.addTopic(topic);
|
||||
const topicIds = repository.topicsInCategories([topic.categoryId]);
|
||||
|
||||
// Then
|
||||
expect(topicIds).toEqual([topic.id]);
|
||||
});
|
||||
|
||||
it("topicsInCategories with several categoryIds returns all matching topics", () => {
|
||||
// Given
|
||||
const db = new Database(":memory:");
|
||||
const url = "http://example.com";
|
||||
const repository = new SqliteMirrorRepository(db, url);
|
||||
const topic1: Topic = {
|
||||
id: 123,
|
||||
categoryId: 42,
|
||||
title: "Sample topic 1",
|
||||
timestampMs: 456789,
|
||||
bumpedMs: 456999,
|
||||
authorUsername: "credbot",
|
||||
};
|
||||
const topic2: Topic = {
|
||||
id: 456,
|
||||
categoryId: 16,
|
||||
title: "Sample topic 2",
|
||||
timestampMs: 456789,
|
||||
bumpedMs: 456999,
|
||||
authorUsername: "credbot",
|
||||
};
|
||||
|
||||
// When
|
||||
repository.addTopic(topic1);
|
||||
repository.addTopic(topic2);
|
||||
const topicIds = repository.topicsInCategories([
|
||||
topic1.categoryId,
|
||||
topic2.categoryId,
|
||||
]);
|
||||
|
||||
// Then
|
||||
expect(topicIds).toEqual([topic1.id, topic2.id]);
|
||||
});
|
||||
|
||||
it("topicsInCategories without categoryIds gives no topicIds", () => {
|
||||
// Given
|
||||
const db = new Database(":memory:");
|
||||
const url = "http://example.com";
|
||||
const repository = new SqliteMirrorRepository(db, url);
|
||||
const topic: Topic = {
|
||||
id: 123,
|
||||
categoryId: 42,
|
||||
title: "Sample topic",
|
||||
timestampMs: 456789,
|
||||
bumpedMs: 456999,
|
||||
authorUsername: "credbot",
|
||||
};
|
||||
|
||||
// When
|
||||
repository.addTopic(topic);
|
||||
const topicIds = repository.topicsInCategories([]);
|
||||
|
||||
// Then
|
||||
expect(topicIds).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue