From 734ed0b4144140498170c7ce88e7d03c582dca60 Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Thu, 6 Jun 2024 13:45:02 -0500 Subject: [PATCH] Added selectRaw to permitted options for posts model (#20340) ref https://linear.app/tryghost/issue/CFR-29/ - this allows our content api requests to omit fields we do not use, improving performance --- .../utils/serializers/input/pages.js | 11 +---- ghost/core/core/server/models/post.js | 2 +- ghost/core/test/e2e-api/content/posts.test.js | 42 +++++++++++++++++++ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/ghost/core/core/server/api/endpoints/utils/serializers/input/pages.js b/ghost/core/core/server/api/endpoints/utils/serializers/input/pages.js index 52ec3626b3..19c58aa306 100644 --- a/ghost/core/core/server/api/endpoints/utils/serializers/input/pages.js +++ b/ghost/core/core/server/api/endpoints/utils/serializers/input/pages.js @@ -37,18 +37,11 @@ function defaultRelations(frame) { } function setDefaultOrder(frame) { - let includesOrderedRelations = false; - - if (frame.options.withRelated) { - const orderedRelations = ['author', 'authors', 'tag', 'tags']; - includesOrderedRelations = _.intersection(orderedRelations, frame.options.withRelated).length > 0; - } - - if (!frame.options.order && !includesOrderedRelations && frame.options.filter) { + if (!frame.options.order && frame.options.filter) { frame.options.autoOrder = slugFilterOrder('posts', frame.options.filter); } - if (!frame.options.order && !frame.options.autoOrder && !includesOrderedRelations) { + if (!frame.options.order && !frame.options.autoOrder) { frame.options.order = 'title asc'; } } diff --git a/ghost/core/core/server/models/post.js b/ghost/core/core/server/models/post.js index 19ad820765..c1313faa76 100644 --- a/ghost/core/core/server/models/post.js +++ b/ghost/core/core/server/models/post.js @@ -1260,7 +1260,7 @@ Post = ghostBookshelf.Model.extend({ // these are the only options that can be passed to Bookshelf / Knex. const validOptions = { findOne: ['columns', 'importing', 'withRelated', 'require', 'filter'], - findPage: ['status'], + findPage: ['status','selectRaw'], findAll: ['columns', 'filter'], destroy: ['destroyAll', 'destroyBy'], diff --git a/ghost/core/test/e2e-api/content/posts.test.js b/ghost/core/test/e2e-api/content/posts.test.js index f5280b7a72..7eeba91d84 100644 --- a/ghost/core/test/e2e-api/content/posts.test.js +++ b/ghost/core/test/e2e-api/content/posts.test.js @@ -22,6 +22,28 @@ const postMatcherShallowIncludes = Object.assign( } ); +async function trackDb(fn, skip) { + const db = require('../../../core/server/data/db'); + if (db?.knex?.client?.config?.client !== 'sqlite3') { + return skip(); + } + /** @type {import('sqlite3').Database} */ + const database = db.knex.client; + + const queries = []; + function handler(/** @type {{sql: string}} */ query) { + queries.push(query); + } + + database.on('query', handler); + + await fn(); + + database.off('query', handler); + + return queries; +} + describe('Posts Content API', function () { let agent; @@ -420,4 +442,24 @@ describe('Posts Content API', function () { .expectStatus(200); assert(response.body.posts[0].html.includes('LinkTest'), 'Html not expected: ' + response.body.posts[0].html); }); + + it('Does not select * by default', async function () { + let queries = await trackDb(() => agent.get('posts/?limit=all').expectStatus(200), this.skip.bind(this)); + let postsRelatedQueries = queries.filter(q => q.sql.includes('`posts`')); + for (const query of postsRelatedQueries) { + assert(!query.sql.includes('*'), 'Query should not select *'); + } + + queries = await trackDb(() => agent.get('posts/?limit=3').expectStatus(200), this.skip.bind(this)); + postsRelatedQueries = queries.filter(q => q.sql.includes('`posts`')); + for (const query of postsRelatedQueries) { + assert(!query.sql.includes('*'), 'Query should not select *'); + } + + queries = await trackDb(() => agent.get('posts/?include=tags,authors').expectStatus(200), this.skip.bind(this)); + postsRelatedQueries = queries.filter(q => q.sql.includes('`posts`')); + for (const query of postsRelatedQueries) { + assert(!query.sql.includes('*'), 'Query should not select *'); + } + }); });