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

View File

@ -1,6 +1,7 @@
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import database from '../database'; import database from '../database';
import { getRoleById } from '../database/services/Role';
import log from '../../utils/log'; import log from '../../utils/log';
import { store as reduxStore } from '../auxStore'; import { store as reduxStore } from '../auxStore';
import { removeRoles, setRoles as setRolesAction, updateRoles } from '../../actions/roles'; import { removeRoles, setRoles as setRolesAction, updateRoles } from '../../actions/roles';
@ -20,41 +21,38 @@ export async function onRolesChanged(ddpMessage) {
const db = database.active; const db = database.active;
const rolesCollection = db.get('roles'); const rolesCollection = db.get('roles');
try { try {
const rolesRecord = await rolesCollection.find(_id); const roleRecord = await getRoleById(_id);
try { if (roleRecord) {
await db.action(async () => { await db.write(async () => {
await rolesRecord.update(u => { await roleRecord.update(u => {
u.description = description; u.description = description;
}); });
}); });
} catch (e) { } else {
log(e); await db.write(async () => {
}
reduxStore.dispatch(updateRoles(_id, description));
} catch (err) {
try {
await db.action(async () => {
await rolesCollection.create(post => { await rolesCollection.create(post => {
post._raw = sanitizedRaw({ id: _id, description }, rolesCollection.schema); post._raw = sanitizedRaw({ id: _id, description }, rolesCollection.schema);
}); });
}); });
} catch (e) {
log(e);
} }
reduxStore.dispatch(updateRoles(_id, description || _id)); reduxStore.dispatch(updateRoles(_id, description || _id));
} catch (e) {
log(e);
} }
} }
if (/removed/.test(type)) { if (/removed/.test(type)) {
const db = database.active; const db = database.active;
const rolesCollection = db.get('roles'); const rolesCollection = db.get('roles');
try { try {
const rolesRecord = await rolesCollection.find(_id); const roleRecord = await getRoleById(_id);
await db.action(async () => { if (roleRecord) {
await rolesRecord.destroyPermanently(); await db.write(async () => {
await roleRecord.destroyPermanently();
}); });
reduxStore.dispatch(removeRoles(_id)); 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 protectedFunction from '../helpers/protectedFunction';
import buildMessage from '../helpers/buildMessage'; import buildMessage from '../helpers/buildMessage';
import database from '../../database'; 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 reduxStore from '../../createStore';
import { addUserTyping, clearUserTyping, removeUserTyping } from '../../../actions/usersTyping'; import { addUserTyping, clearUserTyping, removeUserTyping } from '../../../actions/usersTyping';
import debounce from '../../../utils/debounce'; import debounce from '../../../utils/debounce';
@ -170,66 +173,69 @@ export default class RoomSubscription {
// Create or update message // Create or update message
try { try {
const messageRecord = await msgCollection.find(message._id); let operation = null;
if (!messageRecord._hasPendingUpdate) { const messageRecord = await getMessageById(message._id);
const update = messageRecord.prepareUpdate( if (messageRecord) {
operation = messageRecord.prepareUpdate(
protectedFunction(m => { protectedFunction(m => {
Object.assign(m, message); Object.assign(m, message);
}) })
); );
this._messagesBatch[message._id] = update; } else {
} operation = msgCollection.prepareCreate(
} catch {
const create = msgCollection.prepareCreate(
protectedFunction(m => { protectedFunction(m => {
m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema); m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema);
m.subscription.id = this.rid; m.subscription.id = this.rid;
Object.assign(m, message); Object.assign(m, message);
}) })
); );
this._messagesBatch[message._id] = create; }
this._messagesBatch[message._id] = operation;
} catch (e) {
log(e);
} }
// Create or update thread // Create or update thread
if (message.tlm) { if (message.tlm) {
try { try {
const threadRecord = await threadsCollection.find(message._id); let operation = null;
if (!threadRecord._hasPendingUpdate) { const threadRecord = await getThreadById(message._id);
const updateThread = threadRecord.prepareUpdate( if (threadRecord) {
operation = threadRecord.prepareUpdate(
protectedFunction(t => { protectedFunction(t => {
Object.assign(t, message); Object.assign(t, message);
}) })
); );
this._threadsBatch[message._id] = updateThread; } else {
} operation = threadsCollection.prepareCreate(
} catch {
const createThread = threadsCollection.prepareCreate(
protectedFunction(t => { protectedFunction(t => {
t._raw = sanitizedRaw({ id: message._id }, threadsCollection.schema); t._raw = sanitizedRaw({ id: message._id }, threadsCollection.schema);
t.subscription.id = this.rid; t.subscription.id = this.rid;
Object.assign(t, message); Object.assign(t, message);
}) })
); );
this._threadsBatch[message._id] = createThread; }
this._threadsBatch[message._id] = operation;
} catch (e) {
log(e);
} }
} }
// Create or update thread message // Create or update thread message
if (message.tmid) { if (message.tmid) {
try { try {
const threadMessageRecord = await threadMessagesCollection.find(message._id); let operation = null;
if (!threadMessageRecord._hasPendingUpdate) { const threadMessageRecord = await getThreadMessageById(message._id);
const updateThreadMessage = threadMessageRecord.prepareUpdate( if (threadMessageRecord) {
operation = threadMessageRecord.prepareUpdate(
protectedFunction(tm => { protectedFunction(tm => {
Object.assign(tm, message); Object.assign(tm, message);
tm.rid = message.tmid; tm.rid = message.tmid;
delete tm.tmid; delete tm.tmid;
}) })
); );
this._threadMessagesBatch[message._id] = updateThreadMessage; } else {
} operation = threadMessagesCollection.prepareCreate(
} catch {
const createThreadMessage = threadMessagesCollection.prepareCreate(
protectedFunction(tm => { protectedFunction(tm => {
tm._raw = sanitizedRaw({ id: message._id }, threadMessagesCollection.schema); tm._raw = sanitizedRaw({ id: message._id }, threadMessagesCollection.schema);
Object.assign(tm, message); Object.assign(tm, message);
@ -238,7 +244,10 @@ export default class RoomSubscription {
delete tm.tmid; 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); sub = await subCollection.find(rid);
} catch (error) { } catch (error) {
sub = { id: rid }; 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)]; 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 // filter loaders to delete
let loadersToDelete = allMessagesRecords.filter(i1 => update.find(i2 => i1.id === generateLoadMoreId(i2._id))); 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 // Create
msgsToCreate = msgsToCreate.map(message => msgsToCreate = msgsToCreate.map(message =>
msgCollection.prepareCreate( msgCollection.prepareCreate(
@ -92,34 +111,31 @@ export default function updateMessages({ rid, update = [], remove = [], loaderIt
// Update // Update
msgsToUpdate = msgsToUpdate.map(message => { msgsToUpdate = msgsToUpdate.map(message => {
const newMessage = update.find(m => m._id === message.id); const newMessage = update.find(m => m._id === message.id);
if (message._hasPendingUpdate) { try {
console.log(message);
return;
}
return message.prepareUpdate( return message.prepareUpdate(
protectedFunction(m => { protectedFunction(m => {
Object.assign(m, newMessage); Object.assign(m, newMessage);
}) })
); );
} catch {
return null;
}
}); });
threadsToUpdate = threadsToUpdate.map(thread => { threadsToUpdate = threadsToUpdate.map(thread => {
if (thread._hasPendingUpdate) {
console.log(thread);
return;
}
const newThread = allThreads.find(t => t._id === thread.id); const newThread = allThreads.find(t => t._id === thread.id);
try {
return thread.prepareUpdate( return thread.prepareUpdate(
protectedFunction(t => { protectedFunction(t => {
Object.assign(t, newThread); Object.assign(t, newThread);
}) })
); );
} catch {
return null;
}
}); });
threadMessagesToUpdate = threadMessagesToUpdate.map(threadMessage => { threadMessagesToUpdate = threadMessagesToUpdate.map(threadMessage => {
if (threadMessage._hasPendingUpdate) {
console.log(threadMessage);
return;
}
const newThreadMessage = allThreadMessages.find(t => t._id === threadMessage.id); const newThreadMessage = allThreadMessages.find(t => t._id === threadMessage.id);
try {
return threadMessage.prepareUpdate( return threadMessage.prepareUpdate(
protectedFunction(tm => { protectedFunction(tm => {
Object.assign(tm, newThreadMessage); Object.assign(tm, newThreadMessage);
@ -127,27 +143,11 @@ export default function updateMessages({ rid, update = [], remove = [], loaderIt
delete threadMessage.tmid; 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 = [ const allRecords = [
...msgsToCreate, ...msgsToCreate,
...msgsToUpdate, ...msgsToUpdate,

View File

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