mirror of
https://github.com/hexastack/hexabot
synced 2025-06-26 18:27:28 +00:00
fix: extra enhancements
This commit is contained in:
parent
286beee5e6
commit
f93d6c20ae
@ -9,7 +9,7 @@
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule, getModelToken } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Model } from 'mongoose';
|
||||
import { Model, Types } from 'mongoose';
|
||||
|
||||
import {
|
||||
blockFixtures,
|
||||
@ -153,7 +153,7 @@ describe('BlockRepository', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateBlocksInScope', () => {
|
||||
describe('prepareBlocksInCategoryUpdateScope', () => {
|
||||
it('should update blocks within the scope based on category and ids', async () => {
|
||||
jest.spyOn(blockRepository, 'findOne').mockResolvedValue({
|
||||
id: validIds[0],
|
||||
@ -164,7 +164,10 @@ describe('BlockRepository', () => {
|
||||
|
||||
const mockUpdateOne = jest.spyOn(blockRepository, 'updateOne');
|
||||
|
||||
await blockRepository.updateBlocksInScope(validCategory, validIds);
|
||||
await blockRepository.prepareBlocksInCategoryUpdateScope(
|
||||
validCategory,
|
||||
validIds,
|
||||
);
|
||||
|
||||
expect(mockUpdateOne).toHaveBeenCalledWith(validIds[0], {
|
||||
nextBlocks: [validIds[1]],
|
||||
@ -182,13 +185,16 @@ describe('BlockRepository', () => {
|
||||
|
||||
const mockUpdateOne = jest.spyOn(blockRepository, 'updateOne');
|
||||
|
||||
await blockRepository.updateBlocksInScope(validCategory, validIds);
|
||||
await blockRepository.prepareBlocksInCategoryUpdateScope(
|
||||
validCategory,
|
||||
validIds,
|
||||
);
|
||||
|
||||
expect(mockUpdateOne).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateExternalBlocks', () => {
|
||||
describe('prepareBlocksOutOfCategoryUpdateScope', () => {
|
||||
it('should update blocks outside the scope by removing references from attachedBlock', async () => {
|
||||
const otherBlocks = [
|
||||
{
|
||||
@ -200,7 +206,10 @@ describe('BlockRepository', () => {
|
||||
|
||||
const mockUpdateOne = jest.spyOn(blockRepository, 'updateOne');
|
||||
|
||||
await blockRepository.updateExternalBlocks(otherBlocks, validIds);
|
||||
await blockRepository.prepareBlocksOutOfCategoryUpdateScope(
|
||||
otherBlocks,
|
||||
validIds,
|
||||
);
|
||||
|
||||
expect(mockUpdateOne).toHaveBeenCalledWith('64abc1234def567890fedcab', {
|
||||
attachedBlock: null,
|
||||
@ -218,10 +227,12 @@ describe('BlockRepository', () => {
|
||||
|
||||
const mockUpdateOne = jest.spyOn(blockRepository, 'updateOne');
|
||||
|
||||
await blockRepository.updateExternalBlocks(otherBlocks, [validIds[0]]);
|
||||
await blockRepository.prepareBlocksOutOfCategoryUpdateScope(otherBlocks, [
|
||||
validIds[0],
|
||||
]);
|
||||
|
||||
expect(mockUpdateOne).toHaveBeenCalledWith('64abc1234def567890fedcab', {
|
||||
$pull: { nextBlocks: [validIds[1]] },
|
||||
nextBlocks: [new Types.ObjectId(validIds[1])],
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -236,13 +247,13 @@ describe('BlockRepository', () => {
|
||||
},
|
||||
] as Block[]);
|
||||
|
||||
const mockUpdateBlocksInScope = jest.spyOn(
|
||||
const prepareBlocksInCategoryUpdateScope = jest.spyOn(
|
||||
blockRepository,
|
||||
'updateBlocksInScope',
|
||||
'prepareBlocksInCategoryUpdateScope',
|
||||
);
|
||||
const mockUpdateExternalBlocks = jest.spyOn(
|
||||
const prepareBlocksOutOfCategoryUpdateScope = jest.spyOn(
|
||||
blockRepository,
|
||||
'updateExternalBlocks',
|
||||
'prepareBlocksOutOfCategoryUpdateScope',
|
||||
);
|
||||
|
||||
await blockRepository.preUpdateMany(
|
||||
@ -252,11 +263,11 @@ describe('BlockRepository', () => {
|
||||
);
|
||||
|
||||
expect(mockFind).toHaveBeenCalled();
|
||||
expect(mockUpdateBlocksInScope).toHaveBeenCalledWith(
|
||||
expect(prepareBlocksInCategoryUpdateScope).toHaveBeenCalledWith(
|
||||
validCategory,
|
||||
validIds,
|
||||
['64abc1234def567890fedcab'],
|
||||
);
|
||||
expect(mockUpdateExternalBlocks).toHaveBeenCalledWith(
|
||||
expect(prepareBlocksOutOfCategoryUpdateScope).toHaveBeenCalledWith(
|
||||
[
|
||||
{
|
||||
id: '64abc1234def567890fedcab',
|
||||
@ -264,26 +275,26 @@ describe('BlockRepository', () => {
|
||||
nextBlocks: [validIds[0]],
|
||||
},
|
||||
],
|
||||
validIds,
|
||||
['64abc1234def567890fedcab'],
|
||||
);
|
||||
});
|
||||
|
||||
it('should not perform updates if no category is provided', async () => {
|
||||
const mockFind = jest.spyOn(blockRepository, 'find');
|
||||
const mockUpdateBlocksInScope = jest.spyOn(
|
||||
const prepareBlocksInCategoryUpdateScope = jest.spyOn(
|
||||
blockRepository,
|
||||
'updateBlocksInScope',
|
||||
'prepareBlocksInCategoryUpdateScope',
|
||||
);
|
||||
const mockUpdateExternalBlocks = jest.spyOn(
|
||||
const prepareBlocksOutOfCategoryUpdateScope = jest.spyOn(
|
||||
blockRepository,
|
||||
'updateExternalBlocks',
|
||||
'prepareBlocksOutOfCategoryUpdateScope',
|
||||
);
|
||||
|
||||
await blockRepository.preUpdateMany({} as any, {}, {});
|
||||
await blockRepository.preUpdateMany({} as any, {}, { $set: {} });
|
||||
|
||||
expect(mockFind).not.toHaveBeenCalled();
|
||||
expect(mockUpdateBlocksInScope).not.toHaveBeenCalled();
|
||||
expect(mockUpdateExternalBlocks).not.toHaveBeenCalled();
|
||||
expect(prepareBlocksInCategoryUpdateScope).not.toHaveBeenCalled();
|
||||
expect(prepareBlocksOutOfCategoryUpdateScope).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -9,7 +9,7 @@
|
||||
import { Injectable, Optional } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import mongoose, {
|
||||
import {
|
||||
Document,
|
||||
Model,
|
||||
Query,
|
||||
@ -94,27 +94,27 @@ export class BlockRepository extends BaseRepository<
|
||||
| UpdateWithAggregationPipeline
|
||||
| UpdateQuery<Document<Block, any, any>>,
|
||||
): Promise<void> {
|
||||
const movedBlock = await this.findOne(criteria);
|
||||
if (!movedBlock) {
|
||||
return;
|
||||
}
|
||||
const update: BlockUpdateDto = updates?.['$set'];
|
||||
|
||||
if (update?.category) {
|
||||
const movedBlockId = criteria._id;
|
||||
const movedBlock: Block = await this.findOne(criteria);
|
||||
|
||||
if (!movedBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find and update blocks that reference the moved block
|
||||
await this.updateMany(
|
||||
{ nextBlocks: movedBlockId },
|
||||
{ $pull: { nextBlocks: movedBlockId } },
|
||||
{ nextBlocks: movedBlock.id },
|
||||
{ $pull: { nextBlocks: movedBlock.id } },
|
||||
);
|
||||
|
||||
await this.updateMany(
|
||||
{ attachedBlock: movedBlockId },
|
||||
{ attachedBlock: movedBlock.id },
|
||||
{ $set: { attachedBlock: null } },
|
||||
);
|
||||
this.checkDeprecatedAttachmentUrl(update);
|
||||
}
|
||||
|
||||
this.checkDeprecatedAttachmentUrl(update);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,29 +136,32 @@ export class BlockRepository extends BaseRepository<
|
||||
criteria: TFilterQuery<Block>,
|
||||
updates: UpdateQuery<Document<Block, any, any>>,
|
||||
): Promise<void> {
|
||||
if (criteria._id?.$in && updates?.$set?.category) {
|
||||
const ids: string[] = criteria._id?.$in || [];
|
||||
const category: string = updates.$set.category;
|
||||
const categoryId: string = updates.$set.category;
|
||||
if (categoryId) {
|
||||
const movedBlocks = await this.find(criteria);
|
||||
|
||||
// Step 1: Map IDs and Category
|
||||
const objIds = ids.map((id) => new mongoose.Types.ObjectId(id));
|
||||
const objCategory = new mongoose.Types.ObjectId(category);
|
||||
if (movedBlocks.length) {
|
||||
const ids: string[] = movedBlocks.map(({ id }) => id);
|
||||
|
||||
// Step 2: Find other blocks
|
||||
const otherBlocks = await this.find({
|
||||
_id: { $nin: objIds },
|
||||
category: { $ne: objCategory },
|
||||
$or: [
|
||||
{ attachedBlock: { $in: objIds } },
|
||||
{ nextBlocks: { $in: objIds } },
|
||||
],
|
||||
});
|
||||
// Step 1: Map IDs and Category
|
||||
const objIds = ids.map((id) => new Types.ObjectId(id));
|
||||
const objCategoryId = new Types.ObjectId(categoryId);
|
||||
|
||||
// Step 3: Update blocks in the provided scope
|
||||
await this.updateBlocksInScope(category, ids);
|
||||
// Step 2: Find other blocks
|
||||
const otherBlocks = await this.find({
|
||||
_id: { $nin: objIds },
|
||||
category: { $ne: objCategoryId },
|
||||
$or: [
|
||||
{ attachedBlock: { $in: objIds } },
|
||||
{ nextBlocks: { $in: objIds } },
|
||||
],
|
||||
});
|
||||
// Step 3: Update blocks in the provided scope
|
||||
await this.prepareBlocksInCategoryUpdateScope(categoryId, ids);
|
||||
|
||||
// Step 4: Update external blocks
|
||||
await this.updateExternalBlocks(otherBlocks, ids);
|
||||
// Step 4: Update external blocks
|
||||
await this.prepareBlocksOutOfCategoryUpdateScope(otherBlocks, ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,9 +173,12 @@ export class BlockRepository extends BaseRepository<
|
||||
* @param ids - IDs representing the blocks to update.
|
||||
* @returns A promise that resolves once all updates within the scope are complete.
|
||||
*/
|
||||
async updateBlocksInScope(category: string, ids: string[]): Promise<void> {
|
||||
async prepareBlocksInCategoryUpdateScope(
|
||||
category: string,
|
||||
ids: string[],
|
||||
): Promise<void> {
|
||||
for (const id of ids) {
|
||||
const oldState = await this.findOne(id);
|
||||
const oldState: Block = await this.findOne(id);
|
||||
if (oldState.category !== category) {
|
||||
const updatedNextBlocks = oldState.nextBlocks.filter((nextBlock) =>
|
||||
ids.includes(nextBlock),
|
||||
@ -198,7 +204,7 @@ export class BlockRepository extends BaseRepository<
|
||||
* @param ids - An array of the Ids to disassociate.
|
||||
* @returns A promise that resolves once all external block updates are complete.
|
||||
*/
|
||||
async updateExternalBlocks(
|
||||
async prepareBlocksOutOfCategoryUpdateScope(
|
||||
otherBlocks: Block[],
|
||||
ids: string[],
|
||||
): Promise<void> {
|
||||
@ -207,14 +213,12 @@ export class BlockRepository extends BaseRepository<
|
||||
await this.updateOne(block.id, { attachedBlock: null });
|
||||
}
|
||||
|
||||
const updatedNextBlocks = block.nextBlocks.filter(
|
||||
(nextBlock) => !ids.includes(nextBlock),
|
||||
);
|
||||
const nextBlocks = block.nextBlocks
|
||||
.filter((nextBlock) => !ids.includes(nextBlock))
|
||||
.map((id) => new Types.ObjectId(id));
|
||||
|
||||
if (updatedNextBlocks.length > 0) {
|
||||
await this.updateOne(block.id, {
|
||||
$pull: { nextBlocks: updatedNextBlocks },
|
||||
});
|
||||
if (nextBlocks.length > 0) {
|
||||
await this.updateOne(block.id, { nextBlocks });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import { getModelToken } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import mongoose, { Model } from 'mongoose';
|
||||
import { Model, Types } from 'mongoose';
|
||||
|
||||
import { DummyRepository } from '@/utils/test/dummy/repositories/dummy.repository';
|
||||
import { closeInMongodConnection } from '@/utils/test/test';
|
||||
@ -150,7 +150,7 @@ describe('BaseRepository', () => {
|
||||
expect(spyBeforeUpdate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ $useProjection: true }),
|
||||
{
|
||||
_id: new mongoose.Types.ObjectId(created.id),
|
||||
_id: new Types.ObjectId(created.id),
|
||||
},
|
||||
expect.objectContaining({ $set: expect.objectContaining(mockUpdate) }),
|
||||
);
|
||||
@ -202,7 +202,7 @@ describe('BaseRepository', () => {
|
||||
expect(spyBeforeDelete).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ $useProjection: true }),
|
||||
{
|
||||
_id: new mongoose.Types.ObjectId(createdId),
|
||||
_id: new Types.ObjectId(createdId),
|
||||
},
|
||||
);
|
||||
expect(spyAfterDelete).toHaveBeenCalledWith(
|
||||
|
Loading…
Reference in New Issue
Block a user