feat(MM-64361): categoryChannels update ONLY when necessary (#8880)

This commit is contained in:
Rahim Rahman 2025-05-29 13:20:19 -06:00 committed by GitHub
parent 6c53533080
commit 705ed603bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 138 additions and 43 deletions

View file

@ -12,47 +12,55 @@ import type ServerDataOperator from '..';
describe('*** Operator: Category Handlers tests ***', () => {
let operator: ServerDataOperator;
let spyOnHandleRecords: jest.SpyInstance;
beforeAll(async () => {
await DatabaseManager.init(['baseHandler.test.com']);
operator = DatabaseManager.serverDatabases['baseHandler.test.com']!.operator;
spyOnHandleRecords = jest.spyOn(operator, 'handleRecords');
});
it('=> handleCategories: should write to the CATEGORY table', async () => {
expect.assertions(2);
beforeEach(() => {
jest.clearAllMocks();
});
const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords');
const categories: Category[] = [
{
id: 'kjlw9j1ttnxwig7tnqgebg7dtipno',
collapsed: false,
display_name: 'Test',
muted: false,
sort_order: 1,
sorting: 'recent',
team_id: '',
type: 'direct_messages',
},
];
afterAll(async () => {
DatabaseManager.destroyServerDatabase('baseHandler.test.com');
});
await operator.handleCategories({
categories,
prepareRecordsOnly: false,
describe('handleCategories', () => {
it('should write to the CATEGORY table', async () => {
expect.assertions(2);
const categories: Category[] = [
{
id: 'kjlw9j1ttnxwig7tnqgebg7dtipno',
collapsed: false,
display_name: 'Test',
muted: false,
sort_order: 1,
sorting: 'recent',
team_id: '',
type: 'direct_messages',
},
];
await operator.handleCategories({
categories,
prepareRecordsOnly: false,
});
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
expect(spyOnHandleRecords).toHaveBeenCalledWith({
fieldName: 'id',
createOrUpdateRawValues: categories,
tableName: MM_TABLES.SERVER.CATEGORY,
prepareRecordsOnly: false,
transformer: transformCategoryRecord,
}, 'handleCategories');
});
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
expect(spyOnHandleRecords).toHaveBeenCalledWith({
fieldName: 'id',
createOrUpdateRawValues: categories,
tableName: MM_TABLES.SERVER.CATEGORY,
prepareRecordsOnly: false,
transformer: transformCategoryRecord,
}, 'handleCategories');
});
it('=> handleCategoryChannels: should write to the CATEGORY_CHANNEL table', async () => {
expect.assertions(2);
const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords');
describe('handleCategoryChannels', () => {
const categoryChannels: CategoryChannel[] = [
{
id: 'team_id-channel_id',
@ -62,18 +70,79 @@ describe('*** Operator: Category Handlers tests ***', () => {
},
];
await operator.handleCategoryChannels({
categoryChannels,
prepareRecordsOnly: false,
it('should write to the CATEGORY_CHANNEL table', async () => {
expect.assertions(2);
await operator.handleCategoryChannels({
categoryChannels,
prepareRecordsOnly: false,
});
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
expect(spyOnHandleRecords).toHaveBeenCalledWith({
fieldName: 'id',
createOrUpdateRawValues: categoryChannels,
tableName: MM_TABLES.SERVER.CATEGORY_CHANNEL,
prepareRecordsOnly: false,
transformer: transformCategoryChannelRecord,
}, 'handleCategoryChannels');
});
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
expect(spyOnHandleRecords).toHaveBeenCalledWith({
fieldName: 'id',
createOrUpdateRawValues: categoryChannels,
tableName: MM_TABLES.SERVER.CATEGORY_CHANNEL,
prepareRecordsOnly: false,
transformer: transformCategoryChannelRecord,
}, 'handleCategoryChannels');
it('should not update an existing record if no changes are made', async () => {
await operator.handleCategoryChannels({
categoryChannels,
prepareRecordsOnly: false,
});
expect(spyOnHandleRecords).not.toHaveBeenCalled();
});
it('should update an existing record if changes are made', async () => {
await operator.handleCategoryChannels({
categoryChannels: [
{
...categoryChannels[0],
sort_order: 2,
},
],
prepareRecordsOnly: false,
});
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
expect(spyOnHandleRecords).toHaveBeenCalledWith(expect.objectContaining({
createOrUpdateRawValues: [
expect.objectContaining({
sort_order: 2,
}),
],
}), 'handleCategoryChannels');
});
it('should not update when missing id', async () => {
const result = await operator.handleCategoryChannels({
categoryChannels: [
{
...categoryChannels[0],
id: undefined,
},
],
prepareRecordsOnly: false,
});
expect(spyOnHandleRecords).not.toHaveBeenCalled();
expect(result).toEqual([]);
});
it('should return empty array when no category channels are provided', async () => {
const result = await operator.handleCategoryChannels({
categoryChannels: undefined,
prepareRecordsOnly: false,
});
expect(result).toEqual([]);
});
});
});

View file

@ -98,7 +98,33 @@ const CategoryHandler = <TBase extends Constructor<ServerDataOperatorBase>>(supe
return [];
}
const createOrUpdateRawValues = getUniqueRawsBy({raws: categoryChannels, key: 'id'});
const uniqueRaws = getUniqueRawsBy({raws: categoryChannels, key: 'id'}) as CategoryChannel[];
const ids = uniqueRaws.map((c) => c.id).filter((id): id is string => id !== undefined);
const db: Database = this.database;
const exists = await db.get<CategoryChannelModel>(CATEGORY_CHANNEL).query(
Q.where('id', Q.oneOf(ids)),
).fetch();
const categoryChannelMap = new Map<string, CategoryChannelModel>(exists.map((c) => [c.id, c]));
const createOrUpdateRawValues = uniqueRaws.reduce((res: CategoryChannel[], c) => {
if (!c.id) {
return res;
}
const e = categoryChannelMap.get(c.id);
if (!e) {
res.push(c);
} else if (
e.categoryId !== c.category_id ||
e.channelId !== c.channel_id ||
e.sortOrder !== c.sort_order
) {
res.push(c);
}
return res;
}, []);
if (!createOrUpdateRawValues.length) {
return [];
}
return this.handleRecords({
fieldName: 'id',