1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-19 05:09:43 +02:00

fix: Use batch inserts to avoid query size limits

This commit is contained in:
Maksim Eltyshev 2025-05-19 17:27:18 +02:00
parent 3aedbff5d0
commit 652c5e9475

View file

@ -97,50 +97,53 @@ const upgradeDatabase = async () => {
const whereInUserIds = ['0', ...userIds]; const whereInUserIds = ['0', ...userIds];
if (users.length > 0) { if (users.length > 0) {
await trx('user_account').insert( await knex
users.map((user) => ({ .batchInsert(
..._.pick(user, [ 'user_account',
'id', users.map((user) => ({
'email', ..._.pick(user, [
'password', 'id',
'name', 'email',
'username', 'password',
'phone', 'name',
'organization', 'username',
'language', 'phone',
'subscribe_to_own_cards', 'organization',
'created_at', 'language',
'updated_at', 'subscribe_to_own_cards',
'password_changed_at', 'created_at',
]), 'updated_at',
role: user.is_admin ? User.Roles.ADMIN : User.Roles.BOARD_USER, 'password_changed_at',
avatar: user.avatar && { ]),
...user.avatar, role: user.is_admin ? User.Roles.ADMIN : User.Roles.BOARD_USER,
sizeInBytes: 0, avatar: user.avatar && {
}, ...user.avatar,
subscribe_to_card_when_commenting: true, sizeInBytes: 0,
turn_off_recent_card_highlighting: false, },
enable_favorites_by_default: false, subscribe_to_card_when_commenting: true,
default_editor_mode: User.EditorModes.WYSIWYG, turn_off_recent_card_highlighting: false,
default_home_view: User.HomeViews.GROUPED_PROJECTS, enable_favorites_by_default: false,
default_projects_order: User.ProjectOrders.BY_DEFAULT, default_editor_mode: User.EditorModes.WYSIWYG,
is_sso_user: user.is_sso, default_home_view: User.HomeViews.GROUPED_PROJECTS,
is_deactivated: false, default_projects_order: User.ProjectOrders.BY_DEFAULT,
})), is_sso_user: user.is_sso,
); is_deactivated: false,
})),
)
.transacting(trx);
const identityProviderUsers = await trx('identity_provider_user') const identityProviderUsers = await trx('identity_provider_user')
.withSchema('v1') .withSchema('v1')
.whereIn('user_id', whereInUserIds); .whereIn('user_id', whereInUserIds);
if (identityProviderUsers.length > 0) { if (identityProviderUsers.length > 0) {
await trx('identity_provider_user').insert(identityProviderUsers); await knex.batchInsert('identity_provider_user', identityProviderUsers).transacting(trx);
} }
const sessions = await trx('session').withSchema('v1').whereIn('user_id', whereInUserIds); const sessions = await trx('session').withSchema('v1').whereIn('user_id', whereInUserIds);
if (sessions.length > 0) { if (sessions.length > 0) {
await trx('session').insert(sessions); await knex.batchInsert('session', sessions).transacting(trx);
} }
} }
@ -154,47 +157,53 @@ const upgradeDatabase = async () => {
if (projectsWithBackgroundImage.length > 0) { if (projectsWithBackgroundImage.length > 0) {
const createdAt = new Date().toISOString(); const createdAt = new Date().toISOString();
const backgroundImages = await trx('background_image').insert( const backgroundImages = await knex
projectsWithBackgroundImage.map((project) => ({ .batchInsert(
...project.background_image, 'background_image',
project_id: project.id, projectsWithBackgroundImage.map((project) => ({
size_in_bytes: 0, ...project.background_image,
created_at: createdAt, project_id: project.id,
})), size_in_bytes: 0,
['id', 'project_id'], created_at: createdAt,
); })),
)
.returning(['id', 'project_id'])
.transacting(trx);
backgroundImages.forEach((backgroundImage) => { backgroundImages.forEach((backgroundImage) => {
backgroundImageIdByProjectId[backgroundImage.project_id] = backgroundImage.id; backgroundImageIdByProjectId[backgroundImage.project_id] = backgroundImage.id;
}); });
} }
await trx('project').insert( await knex
projects.map((project) => { .batchInsert(
const data = { 'project',
..._.pick(project, ['id', 'name', 'created_at', 'updated_at']), projects.map((project) => {
is_hidden: false, const data = {
}; ..._.pick(project, ['id', 'name', 'created_at', 'updated_at']),
is_hidden: false,
};
if (project.background) { if (project.background) {
data.background_type = project.background.type; data.background_type = project.background.type;
switch (project.background.type) { switch (project.background.type) {
case Project.BackgroundTypes.GRADIENT: case Project.BackgroundTypes.GRADIENT:
data.background_gradient = project.background.name; data.background_gradient = project.background.name;
break; break;
case Project.BackgroundTypes.IMAGE: case Project.BackgroundTypes.IMAGE:
data.background_image_id = backgroundImageIdByProjectId[project.id]; data.background_image_id = backgroundImageIdByProjectId[project.id];
break; break;
default: default:
}
} }
}
return data; return data;
}), }),
); )
.transacting(trx);
} }
const projectManagers = await trx('project_manager') const projectManagers = await trx('project_manager')
@ -202,7 +211,7 @@ const upgradeDatabase = async () => {
.whereIn('project_id', whereInProjectIds); .whereIn('project_id', whereInProjectIds);
if (projectManagers.length > 0) { if (projectManagers.length > 0) {
await trx('project_manager').insert(projectManagers); await knex.batchInsert('project_manager', projectManagers).transacting(trx);
} }
const boards = await trx('board').withSchema('v1').whereIn('project_id', whereInProjectIds); const boards = await trx('board').withSchema('v1').whereIn('project_id', whereInProjectIds);
@ -218,27 +227,33 @@ const upgradeDatabase = async () => {
const whereInBoardIds = ['0', ...Object.keys(projectIdByBoardId)]; const whereInBoardIds = ['0', ...Object.keys(projectIdByBoardId)];
if (boards.length > 0) { if (boards.length > 0) {
await trx('board').insert( await knex
boards.map((board) => ({ .batchInsert(
..._.pick(board, ['id', 'project_id', 'position', 'name', 'created_at', 'updated_at']), 'board',
default_view: Board.Views.KANBAN, boards.map((board) => ({
default_card_type: Card.Types.PROJECT, ..._.pick(board, ['id', 'project_id', 'position', 'name', 'created_at', 'updated_at']),
limit_card_types_to_default_one: false, default_view: Board.Views.KANBAN,
always_display_card_creator: false, default_card_type: Card.Types.PROJECT,
})), limit_card_types_to_default_one: false,
); always_display_card_creator: false,
})),
)
.transacting(trx);
const createdAt = new Date().toISOString(); const createdAt = new Date().toISOString();
await trx('list').insert( await knex
boards.flatMap((board) => .batchInsert(
[List.Types.ARCHIVE, List.Types.TRASH].map((type) => ({ 'list',
type, boards.flatMap((board) =>
board_id: board.id, [List.Types.ARCHIVE, List.Types.TRASH].map((type) => ({
created_at: createdAt, type,
})), board_id: board.id,
), created_at: createdAt,
); })),
),
)
.transacting(trx);
} }
const boardMemberships = await trx('board_membership') const boardMemberships = await trx('board_membership')
@ -246,46 +261,52 @@ const upgradeDatabase = async () => {
.whereIn('board_id', whereInBoardIds); .whereIn('board_id', whereInBoardIds);
if (boardMemberships.length > 0) { if (boardMemberships.length > 0) {
await trx('board_membership').insert( await knex
boardMemberships.map((boardMembership) => ({ .batchInsert(
..._.pick(boardMembership, [ 'board_membership',
'id', boardMemberships.map((boardMembership) => ({
'board_id', ..._.pick(boardMembership, [
'user_id', 'id',
'role', 'board_id',
'can_comment', 'user_id',
'created_at', 'role',
'updated_at', 'can_comment',
]), 'created_at',
project_id: projectIdByBoardId[boardMembership.board_id], 'updated_at',
})), ]),
); project_id: projectIdByBoardId[boardMembership.board_id],
})),
)
.transacting(trx);
} }
const labels = await trx('label').withSchema('v1').whereIn('board_id', whereInBoardIds); const labels = await trx('label').withSchema('v1').whereIn('board_id', whereInBoardIds);
if (labels.length > 0) { if (labels.length > 0) {
await trx('label').insert(labels); await knex.batchInsert('label', labels).transacting(trx);
} }
const lists = await trx('list').withSchema('v1').whereIn('board_id', whereInBoardIds); const lists = await trx('list').withSchema('v1').whereIn('board_id', whereInBoardIds);
const whereInListIds = ['0', ...lists.map(({ id }) => id)]; const whereInListIds = ['0', ...lists.map(({ id }) => id)];
if (lists.length > 0) { if (lists.length > 0) {
await trx('list').insert( await knex
lists.map((list) => ({ .batchInsert(
..._.pick(list, [ 'list',
'id', lists.map((list) => ({
'board_id', ..._.pick(list, [
'position', 'id',
'name', 'board_id',
'color', 'position',
'created_at', 'name',
'updated_at', 'color',
]), 'created_at',
type: List.Types.ACTIVE, 'updated_at',
})), ]),
); type: List.Types.ACTIVE,
})),
)
.transacting(trx);
} }
const cards = await trx('card') const cards = await trx('card')
@ -297,26 +318,29 @@ const upgradeDatabase = async () => {
const whereInCardIds = ['0', ...Object.keys(cardById)]; const whereInCardIds = ['0', ...Object.keys(cardById)];
if (cards.length > 0) { if (cards.length > 0) {
await trx('card').insert( await knex
cards.map((card) => ({ .batchInsert(
..._.pick(card, [ 'card',
'id', cards.map((card) => ({
'board_id', ..._.pick(card, [
'list_id', 'id',
'cover_attachment_id', 'board_id',
'position', 'list_id',
'name', 'cover_attachment_id',
'description', 'position',
'due_date', 'name',
'stopwatch', 'description',
'created_at', 'due_date',
'updated_at', 'stopwatch',
]), 'created_at',
creator_user_id: userIdsSet.has(card.creator_user_id) ? card.creator_user_id : null, 'updated_at',
type: Card.Types.PROJECT, ]),
list_changed_at: card.created_at, creator_user_id: userIdsSet.has(card.creator_user_id) ? card.creator_user_id : null,
})), type: Card.Types.PROJECT,
); list_changed_at: card.created_at,
})),
)
.transacting(trx);
} }
const cardSubscriptions = await trx('card_subscription') const cardSubscriptions = await trx('card_subscription')
@ -324,7 +348,7 @@ const upgradeDatabase = async () => {
.whereIn('card_id', whereInCardIds); .whereIn('card_id', whereInCardIds);
if (cardSubscriptions.length > 0) { if (cardSubscriptions.length > 0) {
await trx('card_subscription').insert(cardSubscriptions); await knex.batchInsert('card_subscription', cardSubscriptions).transacting(trx);
} }
const cardMemberships = await trx('card_membership') const cardMemberships = await trx('card_membership')
@ -332,13 +356,13 @@ const upgradeDatabase = async () => {
.whereIn('card_id', whereInCardIds); .whereIn('card_id', whereInCardIds);
if (cardMemberships.length > 0) { if (cardMemberships.length > 0) {
await trx('card_membership').insert(cardMemberships); await knex.batchInsert('card_membership', cardMemberships).transacting(trx);
} }
const cardLabels = await trx('card_label').withSchema('v1').whereIn('card_id', whereInCardIds); const cardLabels = await trx('card_label').withSchema('v1').whereIn('card_id', whereInCardIds);
if (cardLabels.length > 0) { if (cardLabels.length > 0) {
await trx('card_label').insert(cardLabels); await knex.batchInsert('card_label', cardLabels).transacting(trx);
} }
const tasks = await trx('task').withSchema('v1').whereIn('card_id', whereInCardIds); const tasks = await trx('task').withSchema('v1').whereIn('card_id', whereInCardIds);
@ -349,47 +373,63 @@ const upgradeDatabase = async () => {
if (taskCardIds.length > 0) { if (taskCardIds.length > 0) {
const createdAt = new Date().toISOString(); const createdAt = new Date().toISOString();
const taskLists = await trx('task_list').insert( const taskLists = await knex
taskCardIds.map((cardId) => ({ .batchInsert(
card_id: cardId, 'task_list',
position: POSITION_GAP, taskCardIds.map((cardId) => ({
name: 'Task List', card_id: cardId,
show_on_front_of_card: true, position: POSITION_GAP,
created_at: createdAt, name: 'Task List',
})), show_on_front_of_card: true,
['id', 'card_id'], created_at: createdAt,
);
await trx('task').insert(
taskLists.flatMap((taskList) =>
tasksByCardId[taskList.card_id].map((task) => ({
..._.pick(task, ['id', 'position', 'name', 'is_completed', 'created_at', 'updated_at']),
task_list_id: taskList.id,
})), })),
), )
); .returning(['id', 'card_id'])
.transacting(trx);
await knex
.batchInsert(
'task',
taskLists.flatMap((taskList) =>
tasksByCardId[taskList.card_id].map((task) => ({
..._.pick(task, [
'id',
'position',
'name',
'is_completed',
'created_at',
'updated_at',
]),
task_list_id: taskList.id,
})),
),
)
.transacting(trx);
} }
const attachments = await trx('attachment').withSchema('v1').whereIn('card_id', whereInCardIds); const attachments = await trx('attachment').withSchema('v1').whereIn('card_id', whereInCardIds);
if (attachments.length > 0) { if (attachments.length > 0) {
await trx('attachment').insert( await knex
attachments.map((attachment) => ({ .batchInsert(
..._.pick(attachment, ['id', 'card_id', 'name', 'created_at', 'updated_at']), 'attachment',
creator_user_id: userIdsSet.has(attachment.creator_user_id) attachments.map((attachment) => ({
? attachment.creator_user_id ..._.pick(attachment, ['id', 'card_id', 'name', 'created_at', 'updated_at']),
: null, creator_user_id: userIdsSet.has(attachment.creator_user_id)
type: Attachment.Types.FILE, ? attachment.creator_user_id
data: { : null,
fileReferenceId: attachment.dirname, type: Attachment.Types.FILE,
filename: attachment.filename, data: {
mimeType: mime.getType(attachment.filename), fileReferenceId: attachment.dirname,
sizeInBytes: 0, filename: attachment.filename,
encoding: null, mimeType: mime.getType(attachment.filename),
image: attachment.image, sizeInBytes: 0,
}, encoding: null,
})), image: attachment.image,
); },
})),
)
.transacting(trx);
} }
const actions = await trx('action').withSchema('v1').whereIn('card_id', whereInCardIds); const actions = await trx('action').withSchema('v1').whereIn('card_id', whereInCardIds);
@ -409,52 +449,58 @@ const upgradeDatabase = async () => {
}); });
if (commentActions.length > 0) { if (commentActions.length > 0) {
await trx('comment').insert( await knex
commentActions.map((action) => ({ .batchInsert(
..._.pick(action, ['id', 'card_id', 'created_at', 'updated_at']), 'comment',
user_id: userIdsSet.has(action.user_id) ? action.user_id : null, commentActions.map((action) => ({
text: action.data.text, ..._.pick(action, ['id', 'card_id', 'created_at', 'updated_at']),
})), user_id: userIdsSet.has(action.user_id) ? action.user_id : null,
); text: action.data.text,
})),
)
.transacting(trx);
} }
if (otherActions.length > 0) { if (otherActions.length > 0) {
await trx('action').insert( await knex
otherActions.map((action) => { .batchInsert(
const data = { 'action',
..._.pick(action, ['id', 'card_id', 'type', 'created_at', 'updated_at']), otherActions.map((action) => {
user_id: userIdsSet.has(action.user_id) ? action.user_id : null, const data = {
}; ..._.pick(action, ['id', 'card_id', 'type', 'created_at', 'updated_at']),
user_id: userIdsSet.has(action.user_id) ? action.user_id : null,
};
switch (action.type) { switch (action.type) {
case Action.Types.CREATE_CARD: case Action.Types.CREATE_CARD:
data.data = { data.data = {
list: { list: {
...action.data.list, ...action.data.list,
type: List.Types.ACTIVE, type: List.Types.ACTIVE,
}, },
}; };
break; break;
case Action.Types.MOVE_CARD: case Action.Types.MOVE_CARD:
data.data = { data.data = {
fromList: { fromList: {
...action.data.fromList, ...action.data.fromList,
type: List.Types.ACTIVE, type: List.Types.ACTIVE,
}, },
toList: { toList: {
...action.data.toList, ...action.data.toList,
type: List.Types.ACTIVE, type: List.Types.ACTIVE,
}, },
}; };
break; break;
default: default:
} }
return data; return data;
}), }),
); )
.transacting(trx);
} }
const notifications = await trx('notification') const notifications = await trx('notification')
@ -464,55 +510,58 @@ const upgradeDatabase = async () => {
.whereIn('card_id', whereInCardIds); .whereIn('card_id', whereInCardIds);
if (notifications.length > 0) { if (notifications.length > 0) {
await trx('notification').insert( await knex
notifications.map((notification) => { .batchInsert(
const card = cardById[notification.card_id]; 'notification',
const action = actionById[notification.action_id]; notifications.map((notification) => {
const card = cardById[notification.card_id];
const action = actionById[notification.action_id];
const data = { const data = {
..._.pick(notification, [ ..._.pick(notification, [
'id', 'id',
'user_id', 'user_id',
'card_id', 'card_id',
'is_read', 'is_read',
'created_at', 'created_at',
'updated_at', 'updated_at',
]), ]),
creator_user_id: userIdsSet.has(notification.creator_user_id) creator_user_id: userIdsSet.has(notification.creator_user_id)
? notification.creator_user_id ? notification.creator_user_id
: null, : null,
board_id: card.board_id, board_id: card.board_id,
type: action.type, type: action.type,
}; };
if (action.type === PrevActionTypes.COMMENT_CARD) { if (action.type === PrevActionTypes.COMMENT_CARD) {
Object.assign(data, { Object.assign(data, {
comment_id: action.id, comment_id: action.id,
data: { data: {
card: _.pick(card, ['name']), card: _.pick(card, ['name']),
text: action.data.text, text: action.data.text,
},
});
} else {
Object.assign(data, {
action_id: action.id,
data: {
fromList: {
...action.data.fromList,
type: List.Types.ACTIVE,
}, },
toList: { });
...action.data.toList, } else {
type: List.Types.ACTIVE, Object.assign(data, {
action_id: action.id,
data: {
fromList: {
...action.data.fromList,
type: List.Types.ACTIVE,
},
toList: {
...action.data.toList,
type: List.Types.ACTIVE,
},
card: _.pick(card, ['name']),
}, },
card: _.pick(card, ['name']), });
}, }
});
}
return data; return data;
}), }),
); )
.transacting(trx);
} }
await trx.schema.dropSchema('v1', true); await trx.schema.dropSchema('v1', true);