perf: Reduce data loading on revisions.list endpoint (#13202)

* perf: Reduce data loading on revisions.list endpoint

* test: Cover includeContent option on Document.findByPk

Also fixes a JSDoc typo on the includeViews option.

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Tom Moor
2026-07-30 08:34:17 -04:00
committed by GitHub
co-authored by Claude
parent 2c161b8158
commit a15e66740a
3 changed files with 49 additions and 2 deletions
+17
View File
@@ -300,6 +300,23 @@ describe("#findByPk", () => {
).rejects.toThrow(EmptyResultError);
});
it("should omit content columns when includeContent is false", async () => {
const document = await buildDocument({ text: "# Heading" });
const response = await Document.findByPk(document.id, {
includeContent: false,
});
expect(response?.id).toBe(document.id);
expect(response?.title).toBe(document.title);
expect(response?.dataValues.content).toBeUndefined();
expect(response?.dataValues.text).toBeUndefined();
expect(response?.dataValues.state).toBeUndefined();
const withContent = await Document.findByPk(document.id);
expect(withContent?.dataValues.content).toBeDefined();
expect(withContent?.dataValues.text).toBeDefined();
});
it("should not allow a passed where to override the id", async () => {
const document = await buildDocument();
const other = await buildDocument();
+18 -2
View File
@@ -99,7 +99,12 @@ type AdditionalFindOptions = {
userId?: string;
/** Whether to include the state column in the attributes. */
includeState?: boolean;
/** Whether to views (default: true). */
/**
* Whether to include the content columns in the attributes (default: true).
* Pass false when the document is only needed for authorization.
*/
includeContent?: boolean;
/** Whether to include views (default: true). */
includeViews?: boolean;
/** Whether to reject the query if no document is found. */
rejectOnEmpty?: boolean | Error;
@@ -151,6 +156,11 @@ interface QueryGeneratorWithWhere {
include: [stateIfContentEmpty],
},
},
withoutContent: {
attributes: {
exclude: ["state", "content", "text"],
},
},
withCollection: {
include: [
{
@@ -797,15 +807,21 @@ class Document extends ArchivableModel<
const {
includeViews = true,
includeState = false,
includeContent = true,
userId,
...rest
} = options;
let contentScope = includeState ? "withState" : "withoutState";
if (!includeContent) {
contentScope = "withoutContent";
}
// allow default preloading of collection membership if `userId` is passed in find options
// almost every endpoint needs the collection membership to determine policy permissions.
const scope = this.scope([
"withDrafts",
includeState ? "withState" : "withoutState",
contentScope,
...((includeViews
? [
{
+14
View File
@@ -42,11 +42,14 @@ router.post(
const document = await Document.findByPk(revision.documentId, {
userId: user.id,
includeContent: false,
includeViews: false,
});
authorize(user, "listRevisions", document);
} else if (documentId) {
const document = await Document.findByPk(documentId, {
userId: user.id,
includeViews: false,
});
authorize(user, "listRevisions", document);
revision = Revision.buildFromDocument(document);
@@ -76,6 +79,8 @@ router.post(
});
const document = await Document.findByPk(revision.documentId, {
userId: user.id,
includeContent: false,
includeViews: false,
});
authorize(user, "update", document);
authorize(user, "update", revision);
@@ -110,6 +115,8 @@ router.post(
});
const document = await Document.findByPk(revision.documentId, {
userId: user.id,
includeContent: false,
includeViews: false,
});
authorize(user, "read", document);
authorize(user, "delete", revision);
@@ -139,6 +146,8 @@ router.post(
const document = await Document.findByPk(revision.documentId, {
userId: user.id,
rejectOnEmpty: true,
includeContent: false,
includeViews: false,
});
authorize(user, "listRevisions", document);
@@ -239,10 +248,15 @@ router.post(
const document = await Document.findByPk(documentId, {
userId: user.id,
paranoid: false,
includeContent: false,
includeViews: false,
});
authorize(user, "listRevisions", document);
const revisions = await Revision.findAll({
attributes: {
exclude: ["content", "text"],
},
where: {
documentId: document.id,
},