fix: Optimize query methods

This commit is contained in:
Maksim Eltyshev
2025-11-27 19:09:10 +01:00
parent 26b3cffdab
commit 0023c63be8
8 changed files with 143 additions and 207 deletions

View File

@@ -31,6 +31,14 @@ const makeWhereQueryBuilder = (Model) => (criteria) => {
return ['id = $1', [criteria]]; return ['id = $1', [criteria]];
}; };
const makeRowToModelTransformer = (Model) => {
// eslint-disable-next-line no-underscore-dangle
const transformations = _.invert(Model._transformer._transformations);
return (row) => _.mapKeys(row, (_, key) => transformations[key]);
};
module.exports = { module.exports = {
makeWhereQueryBuilder, makeWhereQueryBuilder,
makeRowToModelTransformer,
}; };

View File

@@ -172,16 +172,7 @@ const delete_ = (criteria) =>
query += `END END, updated_at = $${queryValues.length} WHERE id IN (${inValues.join(', ')}) AND references_total IS NOT NULL RETURNING *`; query += `END END, updated_at = $${queryValues.length} WHERE id IN (${inValues.join(', ')}) AND references_total IS NOT NULL RETURNING *`;
const queryResult = await sails.sendNativeQuery(query, queryValues).usingConnection(db); const queryResult = await sails.sendNativeQuery(query, queryValues).usingConnection(db);
uploadedFiles = queryResult.rows.map((row) => UploadedFile.qm.transformRowToModel(row));
uploadedFiles = queryResult.rows.map((row) => ({
id: row.id,
type: row.type,
mimeType: row.mime_type,
size: row.size,
referencesTotal: row.references_total,
createdAt: row.created_at,
updatedAt: row.updated_at,
}));
} }
return { attachments, uploadedFiles }; return { attachments, uploadedFiles };
@@ -200,17 +191,7 @@ const deleteOne = (criteria) =>
) )
.usingConnection(db); .usingConnection(db);
const [row] = queryResult.rows; uploadedFile = UploadedFile.qm.transformRowToModel(queryResult.rows[0]);
uploadedFile = {
id: row.id,
type: row.type,
mimeType: row.mime_type,
size: row.size,
referencesTotal: row.references_total,
createdAt: row.created_at,
updatedAt: row.updated_at,
};
} }
return { attachment, uploadedFile }; return { attachment, uploadedFile };

View File

@@ -105,16 +105,7 @@ const delete_ = (criteria) =>
query += `END END, updated_at = $${queryValues.length} WHERE id IN (${inValues.join(', ')}) AND references_total IS NOT NULL RETURNING *`; query += `END END, updated_at = $${queryValues.length} WHERE id IN (${inValues.join(', ')}) AND references_total IS NOT NULL RETURNING *`;
const queryResult = await sails.sendNativeQuery(query, queryValues).usingConnection(db); const queryResult = await sails.sendNativeQuery(query, queryValues).usingConnection(db);
uploadedFiles = queryResult.rows.map((row) => UploadedFile.qm.transformRowToModel(row));
uploadedFiles = queryResult.rows.map((row) => ({
id: row.id,
type: row.type,
mimeType: row.mime_type,
size: row.size,
referencesTotal: row.references_total,
createdAt: row.created_at,
updatedAt: row.updated_at,
}));
} }
return { backgroundImages, uploadedFiles }; return { backgroundImages, uploadedFiles };
@@ -131,17 +122,7 @@ const deleteOne = (criteria) =>
) )
.usingConnection(db); .usingConnection(db);
const [row] = queryResult.rows; const uploadedFile = UploadedFile.qm.transformRowToModel(queryResult.rows[0]);
uploadedFile = {
id: row.id,
type: row.type,
mimeType: row.mime_type,
size: row.size,
referencesTotal: row.references_total,
createdAt: row.created_at,
updatedAt: row.updated_at,
};
return { backgroundImage, uploadedFile }; return { backgroundImage, uploadedFile };
}); });

View File

@@ -4,15 +4,42 @@
*/ */
const buildSearchParts = require('../../../../utils/build-query-parts'); const buildSearchParts = require('../../../../utils/build-query-parts');
const { makeRowToModelTransformer } = require('../helpers');
const LIMIT = 50; const LIMIT = 50;
const transformRowToModel = makeRowToModelTransformer(Card);
const defaultFind = (criteria, { sort = 'id', limit } = {}) => const defaultFind = (criteria, { sort = 'id', limit } = {}) =>
Card.find(criteria).sort(sort).limit(limit); Card.find(criteria).sort(sort).limit(limit);
/* Query methods */ /* Query methods */
const getIdsByEndlessListId = async (listId, { before, search, userIds, labelIds } = {}) => { const createOne = (values) => Card.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByBoardId = (boardId) =>
defaultFind({
boardId,
});
const getByListId = async (listId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) => {
const criteria = {
listId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
return defaultFind(criteria, { sort });
};
const getByEndlessListId = async (listId, { before, search, userIds, labelIds }) => {
if (search || userIds || labelIds) {
if (userIds && userIds.length === 0) { if (userIds && userIds.length === 0) {
return []; return [];
} }
@@ -22,7 +49,7 @@ const getIdsByEndlessListId = async (listId, { before, search, userIds, labelIds
} }
const queryValues = []; const queryValues = [];
let query = 'SELECT DISTINCT card.id FROM card'; let query = 'SELECT DISTINCT card.* FROM card';
if (userIds) { if (userIds) {
query += ' LEFT JOIN card_membership ON card.id = card_membership.card_id'; query += ' LEFT JOIN card_membership ON card.id = card_membership.card_id';
@@ -97,49 +124,13 @@ const getIdsByEndlessListId = async (listId, { before, search, userIds, labelIds
throw error; throw error;
} }
return sails.helpers.utils.mapRecords(queryResult.rows); return queryResult.rows.map((row) => transformRowToModel(row));
};
const createOne = (values) => Card.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByBoardId = (boardId) =>
defaultFind({
boardId,
});
const getByListId = async (listId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) => {
const criteria = {
listId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
} }
return defaultFind(criteria, { sort }); const criteria = {
}; and: [{ listId }],
const getByEndlessListId = async (listId, { before, search, userIds, labelIds }) => {
const criteria = {};
const options = {
sort: ['listChangedAt DESC', 'id DESC'],
}; };
if (search || userIds || labelIds) {
criteria.id = await getIdsByEndlessListId(listId, {
before,
search,
userIds,
labelIds,
});
} else {
criteria.and = [{ listId }];
if (before) { if (before) {
criteria.and.push({ criteria.and.push({
or: [ or: [
@@ -158,10 +149,10 @@ const getByEndlessListId = async (listId, { before, search, userIds, labelIds })
}); });
} }
options.limit = LIMIT; return defaultFind(criteria, {
} sort: ['listChangedAt DESC', 'id DESC'],
limit: LIMIT,
return defaultFind(criteria, options); });
}; };
const getByListIds = async (listIds, { sort = ['position', 'id'] } = {}) => const getByListIds = async (listIds, { sort = ['position', 'id'] } = {}) =>
@@ -242,8 +233,6 @@ const delete_ = (criteria) => Card.destroy(criteria).fetch();
const deleteOne = (criteria) => Card.destroyOne(criteria); const deleteOne = (criteria) => Card.destroyOne(criteria);
module.exports = { module.exports = {
getIdsByEndlessListId,
createOne, createOne,
getByIds, getByIds,
getByBoardId, getByBoardId,

View File

@@ -3,6 +3,10 @@
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/ */
const { makeRowToModelTransformer } = require('../helpers');
const transformRowToModel = makeRowToModelTransformer(CustomFieldValue);
const defaultFind = (criteria, { customFieldGroupIdOrIds }) => { const defaultFind = (criteria, { customFieldGroupIdOrIds }) => {
if (customFieldGroupIdOrIds) { if (customFieldGroupIdOrIds) {
criteria.customFieldGroupId = customFieldGroupIdOrIds; // eslint-disable-line no-param-reassign criteria.customFieldGroupId = customFieldGroupIdOrIds; // eslint-disable-line no-param-reassign
@@ -32,17 +36,7 @@ const createOrUpdateOne = async (values) => {
new Date().toISOString(), new Date().toISOString(),
]); ]);
const [row] = queryResult.rows; return transformRowToModel(queryResult.rows[0]);
return {
id: row.id,
cardId: row.card_id,
customFieldGroupId: row.custom_field_group_id,
customFieldId: row.custom_field_id,
content: row.content,
createdAt: row.created_at,
updatedAt: row.updated_at,
};
}; };
const getByIds = (ids) => defaultFind(ids); const getByIds = (ids) => defaultFind(ids);

View File

@@ -3,9 +3,10 @@
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/ */
const { makeWhereQueryBuilder } = require('../helpers'); const { makeRowToModelTransformer, makeWhereQueryBuilder } = require('../helpers');
const buildWhereQuery = makeWhereQueryBuilder(List); const buildWhereQuery = makeWhereQueryBuilder(List);
const transformRowToModel = makeRowToModelTransformer(List);
const defaultFind = (criteria, { sort = 'id' } = {}) => List.find(criteria).sort(sort); const defaultFind = (criteria, { sort = 'id' } = {}) => List.find(criteria).sort(sort);
@@ -67,10 +68,7 @@ const updateOne = async (criteria, values) => {
return { list: null }; return { list: null };
} }
const prev = { const prev = transformRowToModel(queryResult.rows[0]);
boardId: queryResult.rows[0].board_id,
type: queryResult.rows[0].type,
};
const list = await List.updateOne(criteria) const list = await List.updateOne(criteria)
.set({ ...values }) .set({ ...values })

View File

@@ -3,12 +3,16 @@
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/ */
const { makeRowToModelTransformer } = require('../helpers');
const COLUMN_NAME_BY_TYPE = { const COLUMN_NAME_BY_TYPE = {
[UploadedFile.Types.USER_AVATAR]: 'user_avatars', [UploadedFile.Types.USER_AVATAR]: 'user_avatars',
[UploadedFile.Types.BACKGROUND_IMAGE]: 'background_images', [UploadedFile.Types.BACKGROUND_IMAGE]: 'background_images',
[UploadedFile.Types.ATTACHMENT]: 'attachments', [UploadedFile.Types.ATTACHMENT]: 'attachments',
}; };
const transformRowToModel = makeRowToModelTransformer(UploadedFile);
/* Query methods */ /* Query methods */
const createOne = (values) => const createOne = (values) =>
@@ -47,4 +51,6 @@ const deleteOne = (criteria) =>
module.exports = { module.exports = {
createOne, createOne,
deleteOne, deleteOne,
transformRowToModel,
}; };

View File

@@ -3,7 +3,7 @@
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/ */
const { makeWhereQueryBuilder } = require('../helpers'); const { makeRowToModelTransformer, makeWhereQueryBuilder } = require('../helpers');
const hasAvatarChanged = (avatar, prevAvatar) => { const hasAvatarChanged = (avatar, prevAvatar) => {
if (!avatar && !prevAvatar) { if (!avatar && !prevAvatar) {
@@ -18,6 +18,7 @@ const hasAvatarChanged = (avatar, prevAvatar) => {
}; };
const buildWhereQuery = makeWhereQueryBuilder(User); const buildWhereQuery = makeWhereQueryBuilder(User);
const transformRowToModel = makeRowToModelTransformer(User);
const defaultFind = (criteria) => User.find(criteria).sort('id'); const defaultFind = (criteria) => User.find(criteria).sort('id');
@@ -117,9 +118,7 @@ const updateOne = async (criteria, values) => {
return { user: null }; return { user: null };
} }
prev = { prev = transformRowToModel(queryResult.rows[0]);
avatar: queryResult.rows[0].avatar,
};
} }
const user = await User.updateOne(criteria) const user = await User.updateOne(criteria)
@@ -136,17 +135,7 @@ const updateOne = async (criteria, values) => {
) )
.usingConnection(db); .usingConnection(db);
const [row] = queryResult.rows; uploadedFile = UploadedFile.qm.transformRowToModel(queryResult.rows[0]);
uploadedFile = {
id: row.id,
type: row.type,
mimeType: row.mime_type,
size: row.size,
referencesTotal: row.references_total,
createdAt: row.created_at,
updatedAt: row.updated_at,
};
} }
if (user.avatar) { if (user.avatar) {
@@ -184,17 +173,7 @@ const deleteOne = (criteria) =>
) )
.usingConnection(db); .usingConnection(db);
const [row] = queryResult.rows; uploadedFile = UploadedFile.qm.transformRowToModel(queryResult.rows[0]);
uploadedFile = {
id: row.id,
type: row.type,
mimeType: row.mime_type,
size: row.size,
referencesTotal: row.references_total,
createdAt: row.created_at,
updatedAt: row.updated_at,
};
} }
return { user, uploadedFile }; return { user, uploadedFile };