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
This commit is contained in:
Steve Larson 2024-06-06 13:45:02 -05:00 committed by GitHub
parent bd030c47bb
commit 734ed0b414
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 45 additions and 10 deletions

View File

@ -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';
}
}

View File

@ -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'],

View File

@ -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('<a href="https://example.com">Link</a><a href="invalid">Test</a>'), '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 *');
}
});
});