[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:
parent
ae47f14070
commit
88d33b42c2
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
|
@ -240,15 +240,15 @@ class Encryption {
|
||||||
msg,
|
msg,
|
||||||
tmsg
|
tmsg
|
||||||
});
|
});
|
||||||
if (message._hasPendingUpdate) {
|
try {
|
||||||
console.log(message);
|
return message.prepareUpdate(
|
||||||
return;
|
protectedFunction(m => {
|
||||||
|
Object.assign(m, newMessage);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return message.prepareUpdate(
|
|
||||||
protectedFunction(m => {
|
|
||||||
Object.assign(m, newMessage);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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 sub.prepareUpdate(
|
||||||
return;
|
protectedFunction(m => {
|
||||||
|
Object.assign(m, newSub);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return sub.prepareUpdate(
|
|
||||||
protectedFunction(m => {
|
|
||||||
Object.assign(m, newSub);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
});
|
||||||
} catch (err) {
|
reduxStore.dispatch(removeRoles(_id));
|
||||||
console.log(err);
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,75 +173,81 @@ 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(
|
||||||
|
protectedFunction(m => {
|
||||||
|
m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema);
|
||||||
|
m.subscription.id = this.rid;
|
||||||
|
Object.assign(m, message);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch {
|
this._messagesBatch[message._id] = operation;
|
||||||
const create = msgCollection.prepareCreate(
|
} catch (e) {
|
||||||
protectedFunction(m => {
|
log(e);
|
||||||
m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema);
|
|
||||||
m.subscription.id = this.rid;
|
|
||||||
Object.assign(m, message);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this._messagesBatch[message._id] = create;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(
|
||||||
|
protectedFunction(t => {
|
||||||
|
t._raw = sanitizedRaw({ id: message._id }, threadsCollection.schema);
|
||||||
|
t.subscription.id = this.rid;
|
||||||
|
Object.assign(t, message);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch {
|
this._threadsBatch[message._id] = operation;
|
||||||
const createThread = threadsCollection.prepareCreate(
|
} catch (e) {
|
||||||
protectedFunction(t => {
|
log(e);
|
||||||
t._raw = sanitizedRaw({ id: message._id }, threadsCollection.schema);
|
|
||||||
t.subscription.id = this.rid;
|
|
||||||
Object.assign(t, message);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this._threadsBatch[message._id] = createThread;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(
|
||||||
|
protectedFunction(tm => {
|
||||||
|
tm._raw = sanitizedRaw({ id: message._id }, threadMessagesCollection.schema);
|
||||||
|
Object.assign(tm, message);
|
||||||
|
tm.subscription.id = this.rid;
|
||||||
|
tm.rid = message.tmid;
|
||||||
|
delete tm.tmid;
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch {
|
this._threadMessagesBatch[message._id] = operation;
|
||||||
const createThreadMessage = threadMessagesCollection.prepareCreate(
|
} catch (e) {
|
||||||
protectedFunction(tm => {
|
log(e);
|
||||||
tm._raw = sanitizedRaw({ id: message._id }, threadMessagesCollection.schema);
|
|
||||||
Object.assign(tm, message);
|
|
||||||
tm.subscription.id = this.rid;
|
|
||||||
tm.rid = message.tmid;
|
|
||||||
delete tm.tmid;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this._threadMessagesBatch[message._id] = createThreadMessage;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,62 +111,43 @@ 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 message.prepareUpdate(
|
||||||
return;
|
protectedFunction(m => {
|
||||||
|
Object.assign(m, newMessage);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return message.prepareUpdate(
|
|
||||||
protectedFunction(m => {
|
|
||||||
Object.assign(m, newMessage);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
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);
|
||||||
return thread.prepareUpdate(
|
try {
|
||||||
protectedFunction(t => {
|
return thread.prepareUpdate(
|
||||||
Object.assign(t, newThread);
|
protectedFunction(t => {
|
||||||
})
|
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);
|
||||||
return threadMessage.prepareUpdate(
|
try {
|
||||||
protectedFunction(tm => {
|
return threadMessage.prepareUpdate(
|
||||||
Object.assign(tm, newThreadMessage);
|
protectedFunction(tm => {
|
||||||
tm.rid = threadMessage.tmid;
|
Object.assign(tm, newThreadMessage);
|
||||||
delete threadMessage.tmid;
|
tm.rid = 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,
|
||||||
|
|
|
@ -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,19 +302,18 @@ 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);
|
||||||
return thread.prepareUpdate(
|
try {
|
||||||
protectedFunction((t: any) => {
|
return thread.prepareUpdate(
|
||||||
Object.assign(t, newThread);
|
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 () => {
|
await db.write(async () => {
|
||||||
await db.batch(
|
await db.batch(
|
||||||
...threadsToCreate,
|
...threadsToCreate,
|
||||||
|
|
Loading…
Reference in New Issue