forked from Ivasoft/mattermost-mobile
[Gekidou] Groups + group-memberships deferred fetch (#6370)
* WIP * Actions updated to fetch remote first, and local on error * Groups fetch and save * PR Feedback: prepare vs store and undefined fix * Forgot to add file * Groups Mention WIP * Groups highlight! * Merge, PR Feedback * PR Feedback * PR Feedback: Try/Catch blocks * PR Feedback * Rebased with PR feedback * Exclusion fix, plus id order * Tidies up iterations * Loops updated * Update app/database/operator/server_data_operator/handlers/group.ts Co-authored-by: Avinash Lingaloo <avinashlng1080@gmail.com> * PR Feedback: Remove unnecessary prepare/store methods * Newline ESLint error * Extracts out id generation for group-associations * Batches if not fetchOnly Co-authored-by: Avinash Lingaloo <avinashlng1080@gmail.com>
This commit is contained in:
@@ -2,16 +2,21 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {transformGroupRecord} from '@database/operator/server_data_operator/transformers/group';
|
||||
import {transformGroupMembershipRecord, transformGroupRecord} from '@database/operator/server_data_operator/transformers/group';
|
||||
import {getUniqueRawsBy} from '@database/operator/utils/general';
|
||||
import {queryGroupMembershipForMember} from '@queries/servers/group';
|
||||
import {generateGroupAssociationId} from '@utils/groups';
|
||||
import {logWarning} from '@utils/log';
|
||||
|
||||
import type {HandleGroupArgs} from '@typings/database/database';
|
||||
import type {HandleGroupArgs, HandleGroupMembershipForMemberArgs} from '@typings/database/database';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
|
||||
const {GROUP, GROUP_MEMBERSHIP} = MM_TABLES.SERVER;
|
||||
|
||||
const {GROUP} = MM_TABLES.SERVER;
|
||||
export interface GroupHandlerMix {
|
||||
handleGroups: ({groups, prepareRecordsOnly}: HandleGroupArgs) => Promise<GroupModel[]>;
|
||||
handleGroupMembershipsForMember: ({userId, groups, prepareRecordsOnly}: HandleGroupMembershipForMemberArgs) => Promise<GroupMembershipModel[]>;
|
||||
}
|
||||
|
||||
const GroupHandler = (superclass: any) => class extends superclass implements GroupHandlerMix {
|
||||
@@ -41,6 +46,66 @@ const GroupHandler = (superclass: any) => class extends superclass implements Gr
|
||||
prepareRecordsOnly,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* handleGroupMembershipsForMember: Handler responsible for the Create/Update operations occurring on the GroupMembership table from the 'Server' schema
|
||||
* @param {string} userId
|
||||
* @param {HandleGroupMembershipForMemberArgs} groupMembershipsArgs
|
||||
* @param {GroupMembership[]} groupMembershipsArgs.groupMemberships
|
||||
* @param {boolean} groupMembershipsArgs.prepareRecordsOnly
|
||||
* @throws DataOperatorException
|
||||
* @returns {Promise<GroupMembershipModel[]>}
|
||||
*/
|
||||
handleGroupMembershipsForMember = async ({userId, groups, prepareRecordsOnly = true}: HandleGroupMembershipForMemberArgs): Promise<GroupMembershipModel[]> => {
|
||||
// Get existing group memberships
|
||||
const existingGroupMemberships = await queryGroupMembershipForMember(this.database, userId).fetch();
|
||||
|
||||
let records: GroupMembershipModel[] = [];
|
||||
let rawValues: GroupMembership[] = [];
|
||||
|
||||
// Nothing to add or remove
|
||||
if (!groups?.length && !existingGroupMemberships.length) {
|
||||
return records;
|
||||
} else if (!groups?.length && existingGroupMemberships.length) { // No groups - remove all existing ones
|
||||
records = existingGroupMemberships.map((gm) => gm.prepareDestroyPermanently());
|
||||
} else if (groups?.length && !existingGroupMemberships.length) { // No existing groups - add all new ones
|
||||
rawValues = groups.map((g) => ({id: generateGroupAssociationId(g.id, userId), user_id: userId, group_id: g.id}));
|
||||
} else if (groups?.length && existingGroupMemberships.length) { // If both, we only want to save new ones and delete one's no longer in groups
|
||||
const groupsSet: {[key: string]: GroupMembership} = {};
|
||||
|
||||
for (const g of groups) {
|
||||
groupsSet[`${g.id}`] = {id: generateGroupAssociationId(g.id, userId), user_id: userId, group_id: g.id};
|
||||
}
|
||||
|
||||
for (const gm of existingGroupMemberships) {
|
||||
// Check if existingGroups overlaps with groups
|
||||
if (groupsSet[gm.groupId]) {
|
||||
// If there is an existing group already, we don't need to add it
|
||||
delete groupsSet[gm.groupId];
|
||||
} else {
|
||||
// No group? Remove existing one
|
||||
records.push(gm.prepareDestroyPermanently());
|
||||
}
|
||||
}
|
||||
|
||||
rawValues.push(...Object.values(groupsSet));
|
||||
}
|
||||
|
||||
records.push(...(await this.handleRecords({
|
||||
fieldName: 'id',
|
||||
transformer: transformGroupMembershipRecord,
|
||||
rawValues,
|
||||
tableName: GROUP_MEMBERSHIP,
|
||||
prepareRecordsOnly: true,
|
||||
})));
|
||||
|
||||
// Batch update if there are records
|
||||
if (records.length && !prepareRecordsOnly) {
|
||||
await this.batchRecords(records);
|
||||
}
|
||||
|
||||
return records;
|
||||
};
|
||||
};
|
||||
|
||||
export default GroupHandler;
|
||||
|
||||
Reference in New Issue
Block a user