From c5ba8d39793ac9705ee272ff948f2b6c6bb68309 Mon Sep 17 00:00:00 2001 From: chairulakmal Date: Sat, 26 Aug 2023 19:02:21 +0700 Subject: [PATCH 1/4] Removed bluebird from `Bookshelf.raw-knex` plugin refs #14882 with this the Bluebird is no longer required in ghost/core --- .../server/models/base/plugins/raw-knex.js | 187 +++++++++--------- ghost/core/package.json | 1 - 2 files changed, 91 insertions(+), 97 deletions(-) diff --git a/ghost/core/core/server/models/base/plugins/raw-knex.js b/ghost/core/core/server/models/base/plugins/raw-knex.js index ffdf38fadd6..bb623f84c34 100644 --- a/ghost/core/core/server/models/base/plugins/raw-knex.js +++ b/ghost/core/core/server/models/base/plugins/raw-knex.js @@ -1,7 +1,6 @@ const _ = require('lodash'); const debug = require('@tryghost/debug')('models:base:raw-knex'); const plugins = require('@tryghost/bookshelf-plugins'); -const Promise = require('bluebird'); const schema = require('../../../data/schema'); @@ -17,7 +16,7 @@ module.exports = function (Bookshelf) { * If we e.g. instantiate for each object a model, it takes twice long. */ raw_knex: { - fetchAll: function (options) { + fetchAll: async function (options) { options = options || {}; const nql = require('@tryghost/nql'); @@ -94,114 +93,110 @@ module.exports = function (Bookshelf) { query.where({id: options.id}); } - return query.then((objects) => { - debug('fetched', modelName, filter); + const objects = await query; - if (!objects.length) { - debug('No more entries found'); - return Promise.resolve([]); - } + debug('fetched', modelName, filter); - let props = {}; - - if (!withRelated) { - return _.map(objects, (object) => { - object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ - attributes: object, - related: function (key) { - return object[key]; - }, - serialize: Bookshelf.registry.models[modelName].prototype.serialize, - formatsToJSON: Bookshelf.registry.models[modelName].prototype.formatsToJSON - })(); - - object = Bookshelf.registry.models[modelName].prototype.fixBools(object); - object = Bookshelf.registry.models[modelName].prototype.fixDatesWhenFetch(object); - return object; - }); - } + if (!objects.length) { + debug('No more entries found'); + return Promise.resolve([]); + } + + let props = {}; + + if (!withRelated) { + return objects.map((object) => { + object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ + attributes: object, + related: function (key) { + return object[key]; + }, + serialize: Bookshelf.registry.models[modelName].prototype.serialize, + formatsToJSON: Bookshelf.registry.models[modelName].prototype.formatsToJSON + })(); + + object = Bookshelf.registry.models[modelName].prototype.fixBools(object); + object = Bookshelf.registry.models[modelName].prototype.fixDatesWhenFetch(object); + return object; + }); + } - _.each(withRelated, (withRelatedKey) => { - const relation = relations[withRelatedKey]; + await Promise.all(withRelated.map(async (withRelatedKey) => { + const relation = relations[withRelatedKey]; - props[relation.name] = (() => { - debug('fetch withRelated', relation.name); + debug('fetch withRelated', relation.name); - let relationQuery = Bookshelf.knex(relation.targetTable); + let relationQuery = Bookshelf.knex(relation.targetTable); - // default fields to select - _.each(relation.select, (fieldToSelect) => { - relationQuery.select(fieldToSelect); - }); + // default fields to select + _.each(relation.select, (fieldToSelect) => { + relationQuery.select(fieldToSelect); + }); - // custom fields to select - _.each(withRelatedFields[withRelatedKey], (toSelect) => { - relationQuery.select(toSelect); - }); + // custom fields to select + _.each(withRelatedFields[withRelatedKey], (toSelect) => { + relationQuery.select(toSelect); + }); - relationQuery.innerJoin( - relation.innerJoin.relation, - relation.innerJoin.condition[0], - relation.innerJoin.condition[1], - relation.innerJoin.condition[2] - ); + relationQuery.innerJoin( + relation.innerJoin.relation, + relation.innerJoin.condition[0], + relation.innerJoin.condition[1], + relation.innerJoin.condition[2] + ); - relationQuery.whereIn(relation.whereIn, _.map(objects, 'id')); - relationQuery.orderBy(relation.orderBy); + relationQuery.whereIn(relation.whereIn, objects.map(obj => obj.id)); + relationQuery.orderBy(relation.orderBy); - return relationQuery - .then((queryRelations) => { - debug('fetched withRelated', relation.name); + const queryRelations = await relationQuery; - // arr => obj[post_id] = [...] (faster access) - return queryRelations.reduce((obj, item) => { - if (!obj[item[relation.whereInKey]]) { - obj[item[relation.whereInKey]] = []; - } + debug('fetched withRelated', relation.name); - obj[item[relation.whereInKey]].push(_.omit(item, relation.select)); - return obj; - }, {}); - }); - })(); - }); + const relationResult = queryRelations.reduce((obj, item) => { + if (!obj[item[relation.whereInKey]]) { + obj[item[relation.whereInKey]] = []; + } + + obj[item[relation.whereInKey]].push(_.omit(item, relation.select)); + + return obj; + }, {}); + + props[relation.name] = relationResult; + })); + + const relationsToAttach = await Promise.all( + Object.keys(props).map((relationName) => { + return {[relationName]: Promise.resolve(props[relationName])}; + }) + ).then(results => Object.assign({}, ...results)); + + debug('attach relations', modelName); - return Promise.props(props) - .then((relationsToAttach) => { - debug('attach relations', modelName); - - objects = _.map(objects, (object) => { - _.each(Object.keys(relationsToAttach), (relation) => { - if (!relationsToAttach[relation][object.id]) { - object[relation] = []; - return; - } - - object[relation] = relationsToAttach[relation][object.id]; - }); - - object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ - attributes: object, - _originalOptions: { - withRelated: Object.keys(relationsToAttach) - }, - related: function (key) { - return object[key]; - }, - serialize: Bookshelf.registry.models[modelName].prototype.serialize, - formatsToJSON: Bookshelf.registry.models[modelName].prototype.formatsToJSON - })(); - - object = Bookshelf.registry.models[modelName].prototype.fixBools(object); - object = Bookshelf.registry.models[modelName].prototype.fixDatesWhenFetch(object); - return object; - }); - - debug('attached relations', modelName); - - return objects; - }); + objects.forEach((object) => { + Object.keys(relationsToAttach).forEach((relation) => { + object[relation] = relationsToAttach[relation][object.id] || []; + }) + + object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ + attributes: object, + _originalOptions: { + withRelated: Object.keys(relationsToAttach) + }, + related: function (key) { + return object[key]; + }, + serialize: Bookshelf.registry.models[modelName].prototype.serialize, + formatsToJSON: Bookshelf.registry.models[modelName].prototype.formatsToJSON + })(); + + object = Bookshelf.registry.models[modelName].prototype.fixBools(object); + object = Bookshelf.registry.models[modelName].prototype.fixDatesWhenFetch(object); }); + + debug('attached relations', modelName); + + return objects; } } }); diff --git a/ghost/core/package.json b/ghost/core/package.json index 19bd3279b2a..0825ce4127e 100644 --- a/ghost/core/package.json +++ b/ghost/core/package.json @@ -163,7 +163,6 @@ "@tryghost/zip": "1.1.37", "amperize": "0.6.1", "analytics-node": "6.2.0", - "bluebird": "3.7.2", "body-parser": "1.20.2", "bookshelf": "1.2.0", "bookshelf-relations": "2.6.0", From e625a9f23a9fe3ed08751509b21eb96c4bba018e Mon Sep 17 00:00:00 2001 From: chairulakmal Date: Sat, 26 Aug 2023 19:13:28 +0700 Subject: [PATCH 2/4] fixed missing semicolon warning by linter no refs --- ghost/core/core/server/models/base/plugins/raw-knex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ghost/core/core/server/models/base/plugins/raw-knex.js b/ghost/core/core/server/models/base/plugins/raw-knex.js index bb623f84c34..8a9177fc3ef 100644 --- a/ghost/core/core/server/models/base/plugins/raw-knex.js +++ b/ghost/core/core/server/models/base/plugins/raw-knex.js @@ -176,7 +176,7 @@ module.exports = function (Bookshelf) { objects.forEach((object) => { Object.keys(relationsToAttach).forEach((relation) => { object[relation] = relationsToAttach[relation][object.id] || []; - }) + }); object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ attributes: object, From a8f8ec8a4a4c35fd1f0225786c797f733eae7c5a Mon Sep 17 00:00:00 2001 From: chairulakmal Date: Mon, 28 Aug 2023 10:09:44 +0700 Subject: [PATCH 3/4] Removed bluebird from Bookshelf.raw-knex plugin with minimal changes refs TryGhost#14882 with this the Bluebird is no longer required in ghost/core --- .../server/models/base/plugins/raw-knex.js | 184 +++++++++--------- 1 file changed, 94 insertions(+), 90 deletions(-) diff --git a/ghost/core/core/server/models/base/plugins/raw-knex.js b/ghost/core/core/server/models/base/plugins/raw-knex.js index 8a9177fc3ef..0d2be41b395 100644 --- a/ghost/core/core/server/models/base/plugins/raw-knex.js +++ b/ghost/core/core/server/models/base/plugins/raw-knex.js @@ -16,7 +16,7 @@ module.exports = function (Bookshelf) { * If we e.g. instantiate for each object a model, it takes twice long. */ raw_knex: { - fetchAll: async function (options) { + fetchAll: function (options) { options = options || {}; const nql = require('@tryghost/nql'); @@ -93,110 +93,114 @@ module.exports = function (Bookshelf) { query.where({id: options.id}); } - const objects = await query; + return query.then((objects) => { + debug('fetched', modelName, filter); - debug('fetched', modelName, filter); - - if (!objects.length) { - debug('No more entries found'); - return Promise.resolve([]); - } - - let props = {}; - - if (!withRelated) { - return objects.map((object) => { - object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ - attributes: object, - related: function (key) { - return object[key]; - }, - serialize: Bookshelf.registry.models[modelName].prototype.serialize, - formatsToJSON: Bookshelf.registry.models[modelName].prototype.formatsToJSON - })(); - - object = Bookshelf.registry.models[modelName].prototype.fixBools(object); - object = Bookshelf.registry.models[modelName].prototype.fixDatesWhenFetch(object); - return object; - }); - } - - await Promise.all(withRelated.map(async (withRelatedKey) => { - const relation = relations[withRelatedKey]; - - debug('fetch withRelated', relation.name); - - let relationQuery = Bookshelf.knex(relation.targetTable); - - // default fields to select - _.each(relation.select, (fieldToSelect) => { - relationQuery.select(fieldToSelect); - }); - - // custom fields to select - _.each(withRelatedFields[withRelatedKey], (toSelect) => { - relationQuery.select(toSelect); - }); + if (!objects.length) { + debug('No more entries found'); + return Promise.resolve([]); + } - relationQuery.innerJoin( - relation.innerJoin.relation, - relation.innerJoin.condition[0], - relation.innerJoin.condition[1], - relation.innerJoin.condition[2] - ); + let props = {}; + + if (!withRelated) { + return _.map(objects, (object) => { + object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ + attributes: object, + related: function (key) { + return object[key]; + }, + serialize: Bookshelf.registry.models[modelName].prototype.serialize, + formatsToJSON: Bookshelf.registry.models[modelName].prototype.formatsToJSON + })(); + + object = Bookshelf.registry.models[modelName].prototype.fixBools(object); + object = Bookshelf.registry.models[modelName].prototype.fixDatesWhenFetch(object); + return object; + }); + } - relationQuery.whereIn(relation.whereIn, objects.map(obj => obj.id)); - relationQuery.orderBy(relation.orderBy); + _.each(withRelated, (withRelatedKey) => { + const relation = relations[withRelatedKey]; - const queryRelations = await relationQuery; + props[relation.name] = (() => { + debug('fetch withRelated', relation.name); - debug('fetched withRelated', relation.name); + let relationQuery = Bookshelf.knex(relation.targetTable); - const relationResult = queryRelations.reduce((obj, item) => { - if (!obj[item[relation.whereInKey]]) { - obj[item[relation.whereInKey]] = []; - } + // default fields to select + _.each(relation.select, (fieldToSelect) => { + relationQuery.select(fieldToSelect); + }); - obj[item[relation.whereInKey]].push(_.omit(item, relation.select)); + // custom fields to select + _.each(withRelatedFields[withRelatedKey], (toSelect) => { + relationQuery.select(toSelect); + }); - return obj; - }, {}); + relationQuery.innerJoin( + relation.innerJoin.relation, + relation.innerJoin.condition[0], + relation.innerJoin.condition[1], + relation.innerJoin.condition[2] + ); - props[relation.name] = relationResult; - })); + relationQuery.whereIn(relation.whereIn, _.map(objects, 'id')); + relationQuery.orderBy(relation.orderBy); - const relationsToAttach = await Promise.all( - Object.keys(props).map((relationName) => { - return {[relationName]: Promise.resolve(props[relationName])}; - }) - ).then(results => Object.assign({}, ...results)); + return relationQuery + .then((queryRelations) => { + debug('fetched withRelated', relation.name); - debug('attach relations', modelName); + // arr => obj[post_id] = [...] (faster access) + return queryRelations.reduce((obj, item) => { + if (!obj[item[relation.whereInKey]]) { + obj[item[relation.whereInKey]] = []; + } - objects.forEach((object) => { - Object.keys(relationsToAttach).forEach((relation) => { - object[relation] = relationsToAttach[relation][object.id] || []; + obj[item[relation.whereInKey]].push(_.omit(item, relation.select)); + return obj; + }, {}); + }); + })(); }); - object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ - attributes: object, - _originalOptions: { - withRelated: Object.keys(relationsToAttach) - }, - related: function (key) { - return object[key]; - }, - serialize: Bookshelf.registry.models[modelName].prototype.serialize, - formatsToJSON: Bookshelf.registry.models[modelName].prototype.formatsToJSON - })(); - - object = Bookshelf.registry.models[modelName].prototype.fixBools(object); - object = Bookshelf.registry.models[modelName].prototype.fixDatesWhenFetch(object); + return Promise.all(Object.values(props)) + .then((relationsToAttach) => { + debug('attach relations', modelName); + + objects = _.map(objects, (object) => { + _.each(Object.keys(relationsToAttach), (relation) => { + if (!relationsToAttach[relation][object.id]) { + object[relation] = []; + return; + } + + object[relation] = relationsToAttach[relation][object.id]; + }); + + object = Bookshelf.registry.models[modelName].prototype.toJSON.bind({ + attributes: object, + _originalOptions: { + withRelated: Object.keys(relationsToAttach) + }, + related: function (key) { + return object[key]; + }, + serialize: Bookshelf.registry.models[modelName].prototype.serialize, + formatsToJSON: Bookshelf.registry.models[modelName].prototype.formatsToJSON + })(); + + object = Bookshelf.registry.models[modelName].prototype.fixBools(object); + object = Bookshelf.registry.models[modelName].prototype.fixDatesWhenFetch(object); + return object; + }); + + debug('attached relations', modelName); + + return objects; + }); }); - - debug('attached relations', modelName); - - return objects; } } }); From e65d1dd1a28c3b55550b911057d44adb9d7f1e50 Mon Sep 17 00:00:00 2001 From: chairulakmal Date: Tue, 29 Aug 2023 16:04:49 +0700 Subject: [PATCH 4/4] Modified array returned by Promise.all to reattach the original keys previously returned by Promise.props refs #14882 --- ghost/core/core/server/models/base/plugins/raw-knex.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ghost/core/core/server/models/base/plugins/raw-knex.js b/ghost/core/core/server/models/base/plugins/raw-knex.js index 0d2be41b395..30e76e4d996 100644 --- a/ghost/core/core/server/models/base/plugins/raw-knex.js +++ b/ghost/core/core/server/models/base/plugins/raw-knex.js @@ -166,9 +166,11 @@ module.exports = function (Bookshelf) { }); return Promise.all(Object.values(props)) - .then((relationsToAttach) => { + .then((relationsToAttachArray) => { debug('attach relations', modelName); + const relationsToAttach = _.zipObject(_.keys(props), relationsToAttachArray); + objects = _.map(objects, (object) => { _.each(Object.keys(relationsToAttach), (relation) => { if (!relationsToAttach[relation][object.id]) {