[FIX] Remove deprecated database methods and other database operations (#3686)

* Fix PK error on subscriptions/room

* Instead of checking for pending update, wrap the call on a try catch and return null in case of error

* Generate delete operations before create/update to prevent errors

* Apply same logic on encryption

* Fix database operations on getRoles

* Fix a few database issues found on Bugsnag on ThreadMessagesView

* Run prettier :(
This commit is contained in:
Diego Mello 2022-02-10 17:16:10 -03:00 committed by GitHub
parent ae47f14070
commit 88d33b42c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 166 additions and 136 deletions

View File

@ -0,0 +1,17 @@
import database from '..';
import { TAppDatabase } from '../interfaces';
import { ROLES_TABLE } from '../model';
import { TRoleModel } from '../../../definitions';
const getCollection = (db: TAppDatabase) => db.get(ROLES_TABLE);
export const getRoleById = async (id: string): Promise<TRoleModel | null> => {
const db = database.active;
const roleCollection = getCollection(db);
try {
const result = await roleCollection.find(id);
return result;
} catch (error) {
return null;
}
};

View File

@ -240,15 +240,15 @@ class Encryption {
msg,
tmsg
});
if (message._hasPendingUpdate) {
console.log(message);
return;
}
try {
return message.prepareUpdate(
protectedFunction(m => {
Object.assign(m, newMessage);
})
);
} catch {
return null;
}
})
);
@ -281,15 +281,15 @@ class Encryption {
subsToDecrypt.map(async sub => {
const { rid, lastMessage } = sub;
const newSub = await this.decryptSubscription({ rid, lastMessage });
if (sub._hasPendingUpdate) {
console.log(sub);
return;
}
try {
return sub.prepareUpdate(
protectedFunction(m => {
Object.assign(m, newSub);
})
);
} catch {
return null;
}
})
);
@ -352,13 +352,15 @@ class Encryption {
);
// If the subscription already exists but doesn't have the E2EKey yet
} else if (!subRecord.E2EKey && subscription.E2EKey) {
if (!subRecord._hasPendingUpdate) {
try {
// Let's update the subscription with the received E2EKey
batch.push(
subRecord.prepareUpdate(s => {
s.E2EKey = subscription.E2EKey;
})
);
} catch (e) {
log(e);
}
}

View File

@ -1,6 +1,7 @@
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import database from '../database';
import { getRoleById } from '../database/services/Role';
import log from '../../utils/log';
import { store as reduxStore } from '../auxStore';
import { removeRoles, setRoles as setRolesAction, updateRoles } from '../../actions/roles';
@ -20,41 +21,38 @@ export async function onRolesChanged(ddpMessage) {
const db = database.active;
const rolesCollection = db.get('roles');
try {
const rolesRecord = await rolesCollection.find(_id);
try {
await db.action(async () => {
await rolesRecord.update(u => {
const roleRecord = await getRoleById(_id);
if (roleRecord) {
await db.write(async () => {
await roleRecord.update(u => {
u.description = description;
});
});
} catch (e) {
log(e);
}
reduxStore.dispatch(updateRoles(_id, description));
} catch (err) {
try {
await db.action(async () => {
} else {
await db.write(async () => {
await rolesCollection.create(post => {
post._raw = sanitizedRaw({ id: _id, description }, rolesCollection.schema);
});
});
} catch (e) {
log(e);
}
reduxStore.dispatch(updateRoles(_id, description || _id));
} catch (e) {
log(e);
}
}
if (/removed/.test(type)) {
const db = database.active;
const rolesCollection = db.get('roles');
try {
const rolesRecord = await rolesCollection.find(_id);
await db.action(async () => {
await rolesRecord.destroyPermanently();
const roleRecord = await getRoleById(_id);
if (roleRecord) {
await db.write(async () => {
await roleRecord.destroyPermanently();
});
reduxStore.dispatch(removeRoles(_id));
} catch (err) {
console.log(err);
}
} catch (e) {
log(e);
}
}
}

View File

@ -6,6 +6,9 @@ import log from '../../../utils/log';
import protectedFunction from '../helpers/protectedFunction';
import buildMessage from '../helpers/buildMessage';
import database from '../../database';
import { getMessageById } from '../../database/services/Message';
import { getThreadById } from '../../database/services/Thread';
import { getThreadMessageById } from '../../database/services/ThreadMessage';
import reduxStore from '../../createStore';
import { addUserTyping, clearUserTyping, removeUserTyping } from '../../../actions/usersTyping';
import debounce from '../../../utils/debounce';
@ -170,66 +173,69 @@ export default class RoomSubscription {
// Create or update message
try {
const messageRecord = await msgCollection.find(message._id);
if (!messageRecord._hasPendingUpdate) {
const update = messageRecord.prepareUpdate(
let operation = null;
const messageRecord = await getMessageById(message._id);
if (messageRecord) {
operation = messageRecord.prepareUpdate(
protectedFunction(m => {
Object.assign(m, message);
})
);
this._messagesBatch[message._id] = update;
}
} catch {
const create = msgCollection.prepareCreate(
} else {
operation = msgCollection.prepareCreate(
protectedFunction(m => {
m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema);
m.subscription.id = this.rid;
Object.assign(m, message);
})
);
this._messagesBatch[message._id] = create;
}
this._messagesBatch[message._id] = operation;
} catch (e) {
log(e);
}
// Create or update thread
if (message.tlm) {
try {
const threadRecord = await threadsCollection.find(message._id);
if (!threadRecord._hasPendingUpdate) {
const updateThread = threadRecord.prepareUpdate(
let operation = null;
const threadRecord = await getThreadById(message._id);
if (threadRecord) {
operation = threadRecord.prepareUpdate(
protectedFunction(t => {
Object.assign(t, message);
})
);
this._threadsBatch[message._id] = updateThread;
}
} catch {
const createThread = threadsCollection.prepareCreate(
} else {
operation = threadsCollection.prepareCreate(
protectedFunction(t => {
t._raw = sanitizedRaw({ id: message._id }, threadsCollection.schema);
t.subscription.id = this.rid;
Object.assign(t, message);
})
);
this._threadsBatch[message._id] = createThread;
}
this._threadsBatch[message._id] = operation;
} catch (e) {
log(e);
}
}
// Create or update thread message
if (message.tmid) {
try {
const threadMessageRecord = await threadMessagesCollection.find(message._id);
if (!threadMessageRecord._hasPendingUpdate) {
const updateThreadMessage = threadMessageRecord.prepareUpdate(
let operation = null;
const threadMessageRecord = await getThreadMessageById(message._id);
if (threadMessageRecord) {
operation = threadMessageRecord.prepareUpdate(
protectedFunction(tm => {
Object.assign(tm, message);
tm.rid = message.tmid;
delete tm.tmid;
})
);
this._threadMessagesBatch[message._id] = updateThreadMessage;
}
} catch {
const createThreadMessage = threadMessagesCollection.prepareCreate(
} else {
operation = threadMessagesCollection.prepareCreate(
protectedFunction(tm => {
tm._raw = sanitizedRaw({ id: message._id }, threadMessagesCollection.schema);
Object.assign(tm, message);
@ -238,7 +244,10 @@ export default class RoomSubscription {
delete tm.tmid;
})
);
this._threadMessagesBatch[message._id] = createThreadMessage;
}
this._threadMessagesBatch[message._id] = operation;
} catch (e) {
log(e);
}
}

View File

@ -24,7 +24,7 @@ export default function updateMessages({ rid, update = [], remove = [], loaderIt
sub = await subCollection.find(rid);
} catch (error) {
sub = { id: rid };
console.log('updateMessages: subscription not found');
log(new Error('updateMessages: subscription not found'));
}
const messagesIds = [...update.map(m => m._id), ...remove.map(m => m._id)];
@ -58,6 +58,25 @@ export default function updateMessages({ rid, update = [], remove = [], loaderIt
// filter loaders to delete
let loadersToDelete = allMessagesRecords.filter(i1 => update.find(i2 => i1.id === generateLoadMoreId(i2._id)));
// Delete
let msgsToDelete = [];
let threadsToDelete = [];
let threadMessagesToDelete = [];
if (remove && remove.length) {
msgsToDelete = allMessagesRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
msgsToDelete = msgsToDelete.map(m => m.prepareDestroyPermanently());
threadsToDelete = allThreadsRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
threadsToDelete = threadsToDelete.map(t => t.prepareDestroyPermanently());
threadMessagesToDelete = allThreadMessagesRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
threadMessagesToDelete = threadMessagesToDelete.map(tm => tm.prepareDestroyPermanently());
}
// Delete loaders
loadersToDelete = loadersToDelete.map(m => m.prepareDestroyPermanently());
if (loaderItem) {
loadersToDelete.push(loaderItem.prepareDestroyPermanently());
}
// Create
msgsToCreate = msgsToCreate.map(message =>
msgCollection.prepareCreate(
@ -92,34 +111,31 @@ export default function updateMessages({ rid, update = [], remove = [], loaderIt
// Update
msgsToUpdate = msgsToUpdate.map(message => {
const newMessage = update.find(m => m._id === message.id);
if (message._hasPendingUpdate) {
console.log(message);
return;
}
try {
return message.prepareUpdate(
protectedFunction(m => {
Object.assign(m, newMessage);
})
);
} catch {
return null;
}
});
threadsToUpdate = threadsToUpdate.map(thread => {
if (thread._hasPendingUpdate) {
console.log(thread);
return;
}
const newThread = allThreads.find(t => t._id === thread.id);
try {
return thread.prepareUpdate(
protectedFunction(t => {
Object.assign(t, newThread);
})
);
} catch {
return null;
}
});
threadMessagesToUpdate = threadMessagesToUpdate.map(threadMessage => {
if (threadMessage._hasPendingUpdate) {
console.log(threadMessage);
return;
}
const newThreadMessage = allThreadMessages.find(t => t._id === threadMessage.id);
try {
return threadMessage.prepareUpdate(
protectedFunction(tm => {
Object.assign(tm, newThreadMessage);
@ -127,27 +143,11 @@ export default function updateMessages({ rid, update = [], remove = [], loaderIt
delete threadMessage.tmid;
})
);
} catch {
return null;
}
});
// Delete
let msgsToDelete = [];
let threadsToDelete = [];
let threadMessagesToDelete = [];
if (remove && remove.length) {
msgsToDelete = allMessagesRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
msgsToDelete = msgsToDelete.map(m => m.prepareDestroyPermanently());
threadsToDelete = allThreadsRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
threadsToDelete = threadsToDelete.map(t => t.prepareDestroyPermanently());
threadMessagesToDelete = allThreadMessagesRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
threadMessagesToDelete = threadMessagesToDelete.map(tm => tm.prepareDestroyPermanently());
}
// Delete loaders
loadersToDelete = loadersToDelete.map(m => m.prepareDestroyPermanently());
if (loaderItem) {
loadersToDelete.push(loaderItem.prepareDestroyPermanently());
}
const allRecords = [
...msgsToCreate,
...msgsToUpdate,

View File

@ -281,6 +281,11 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
let threadsToUpdate: any[] = [];
let threadsToDelete: any[] = [];
if (remove && remove.length) {
threadsToDelete = allThreadsRecords.filter((i1: { id: string }) => remove.find(i2 => i1.id === i2._id));
threadsToDelete = threadsToDelete.map(t => t.prepareDestroyPermanently());
}
if (update && update.length) {
update = update.map(m => buildMessage(m));
// filter threads
@ -297,17 +302,16 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
);
threadsToUpdate = threadsToUpdate.map(thread => {
const newThread = update.find(t => t._id === thread.id);
try {
return thread.prepareUpdate(
protectedFunction((t: any) => {
Object.assign(t, newThread);
})
);
});
} catch {
return null;
}
if (remove && remove.length) {
threadsToDelete = allThreadsRecords.filter((i1: { id: string }) => remove.find(i2 => i1.id === i2._id));
threadsToDelete = threadsToDelete.map(t => t.prepareDestroyPermanently());
});
}
await db.write(async () => {