insomnia/packages/insomnia-app/app/common/database.js

738 lines
19 KiB
JavaScript
Raw Normal View History

2017-07-19 00:19:56 +00:00
// @flow
2018-06-25 17:42:50 +00:00
import type { BaseModel } from '../models/index';
import * as models from '../models/index';
import electron from 'electron';
import NeDB from 'nedb';
import fsPath from 'path';
2018-06-25 17:42:50 +00:00
import { DB_PERSIST_INTERVAL } from './constants';
import uuid from 'uuid';
import { getDataDirectory } from './misc';
export const CHANGE_INSERT = 'insert';
export const CHANGE_UPDATE = 'update';
export const CHANGE_REMOVE = 'remove';
2016-09-08 06:54:35 +00:00
const database = {};
const db = {
_empty: true,
};
2016-09-21 21:46:42 +00:00
// ~~~~~~~ //
// HELPERS //
// ~~~~~~~ //
2018-06-25 17:42:50 +00:00
function allTypes() {
2016-11-10 01:15:27 +00:00
return Object.keys(db);
}
2016-04-16 23:24:57 +00:00
2018-06-25 17:42:50 +00:00
function getDBFilePath(modelType) {
// NOTE: Do not EVER change this. EVER!
return fsPath.join(getDataDirectory(), `insomnia.${modelType}.db`);
2016-04-28 00:04:29 +00:00
}
2018-06-25 17:42:50 +00:00
export async function initClient() {
electron.ipcRenderer.on('db.changes', async (e, changes) => {
for (const fn of changeListeners) {
await fn(changes);
}
});
2017-11-22 00:07:28 +00:00
console.log('[db] Initialized DB client');
}
2018-10-17 16:42:33 +00:00
export async function init(types: Array<string>, config: Object = {}, forceReset: boolean = false) {
if (forceReset) {
changeListeners = [];
for (const attr of Object.keys(db)) {
if (attr === '_empty') {
continue;
2016-12-31 19:32:50 +00:00
}
delete db[attr];
}
}
// Fill in the defaults
for (const modelType of types) {
if (db[modelType]) {
console.log(`[db] Already initialized DB.${modelType}`);
continue;
2016-12-30 23:06:27 +00:00
}
const filePath = getDBFilePath(modelType);
2018-06-25 17:42:50 +00:00
const collection = new NeDB(
Object.assign(
{
autoload: true,
filename: filePath,
2018-06-25 17:42:50 +00:00
},
config,
),
2018-06-25 17:42:50 +00:00
);
2016-05-11 05:43:51 +00:00
collection.persistence.setAutocompactionInterval(DB_PERSIST_INTERVAL);
2017-07-19 01:55:47 +00:00
db[modelType] = collection;
2016-11-10 01:15:27 +00:00
}
delete db._empty;
electron.ipcMain.on('db.fn', async (e, fnName, replyChannel, ...args) => {
Version Control (beta) (#1439) * VCS proof of concept underway! * Stuff * Some things * Replace deprecated Electron makeSingleInstance * Rename `window` variables so not to be confused with window object * Don't unnecessarily update request when URL does not change * Regenerate package-lock * Fix tests + ESLint * Publish - insomnia-app@1.0.49 - insomnia-cookies@0.0.12 - insomnia-httpsnippet@1.16.18 - insomnia-importers@2.0.13 - insomnia-libcurl@0.0.23 - insomnia-prettify@0.1.7 - insomnia-url@0.1.6 - insomnia-xpath@1.0.9 - insomnia-plugin-base64@1.0.6 - insomnia-plugin-cookie-jar@1.0.8 - insomnia-plugin-core-themes@1.0.5 - insomnia-plugin-default-headers@1.1.9 - insomnia-plugin-file@1.0.7 - insomnia-plugin-hash@1.0.7 - insomnia-plugin-jsonpath@1.0.12 - insomnia-plugin-now@1.0.11 - insomnia-plugin-os@1.0.13 - insomnia-plugin-prompt@1.1.9 - insomnia-plugin-request@1.0.18 - insomnia-plugin-response@1.0.16 - insomnia-plugin-uuid@1.0.10 * Broken but w/e * Some tweaks * Big refactor. Create local snapshots and push done * POC merging and a lot of improvements * Lots of work done on initial UI/UX * Fix old tests * Atomic writes and size-based batches * Update StageEntry definition once again to be better * Factor out GraphQL query logic * Merge algorithm, history modal, other minor things * Fix test * Merge, checkout, revert w/ user changes now work * Force UI to refresh when switching branches changes active request * Rough draft pull() and some cleanup * E2EE stuff and some refactoring * Add ability to share project with team and fixed tests * VCS now created in root component and better remote project handling * Remove unused definition * Publish - insomnia-account@0.0.2 - insomnia-app@1.1.1 - insomnia-cookies@0.0.14 - insomnia-httpsnippet@1.16.20 - insomnia-importers@2.0.15 - insomnia-libcurl@0.0.25 - insomnia-prettify@0.1.9 - insomnia-sync@0.0.2 - insomnia-url@0.1.8 - insomnia-xpath@1.0.11 - insomnia-plugin-base64@1.0.8 - insomnia-plugin-cookie-jar@1.0.10 - insomnia-plugin-core-themes@1.0.7 - insomnia-plugin-file@1.0.9 - insomnia-plugin-hash@1.0.9 - insomnia-plugin-jsonpath@1.0.14 - insomnia-plugin-now@1.0.13 - insomnia-plugin-os@1.0.15 - insomnia-plugin-prompt@1.1.11 - insomnia-plugin-request@1.0.20 - insomnia-plugin-response@1.0.18 - insomnia-plugin-uuid@1.0.12 * Move some deps around * Fix Flow errors * Update package.json * Fix eslint errors * Fix tests * Update deps * bootstrap insomnia-sync * TRy fixing appveyor * Try something else * Bump lerna * try powershell * Try again * Fix imports * Fixed errors * sync types refactor * Show remote projects in workspace dropdown * Improved pulling of non-local workspaces * Loading indicators and some tweaks * Clean up sync staging modal * Some sync improvements: - No longer store stage - Upgrade Electron - Sync UI/UX improvements * Fix snyc tests * Upgraded deps and hot loader tweaks (it's broken for some reason) * Fix tests * Branches dialog, network refactoring, some tweaks * Fixed merging when other branch is empty * A bunch of small fixes from real testing * Fixed pull merge logic * Fix tests * Some bug fixes * A few small tweaks * Conflict resolution and other improvements * Fix tests * Add revert changes * Deal with duplicate projects per workspace * Some tweaks and accessibility improvements * Tooltip accessibility * Fix API endpoint * Fix tests * Remove jest dep from insomnia-importers
2019-04-18 00:50:03 +00:00
try {
const result = await database[fnName](...args);
e.sender.send(replyChannel, null, result);
} catch (err) {
e.sender.send(replyChannel, { message: err.message, stack: err.stack });
}
});
// NOTE: Only repair the DB if we're not running in memory. Repairing here causes tests to
// hang indefinitely for some reason.
// TODO: Figure out why this makes tests hang
if (!config.inMemoryOnly) {
await _repairDatabase();
}
if (!config.inMemoryOnly) {
console.log(`[db] Initialized DB at ${getDBFilePath('$TYPE')}`);
}
// This isn't the best place for this but w/e
// Listen for response deletions and delete corresponding response body files
onChange(async changes => {
2018-06-18 21:15:15 +00:00
for (const [type, doc] of changes) {
const m: Object | null = models.getModel(doc.type);
if (!m) {
continue;
}
if (type === CHANGE_REMOVE && typeof m.hookRemove === 'function') {
try {
await m.hookRemove(doc);
} catch (err) {
2018-10-17 16:42:33 +00:00
console.log(`[db] Delete hook failed for ${type} ${doc._id}: ${err.message}`);
}
}
if (type === CHANGE_INSERT && typeof m.hookInsert === 'function') {
try {
await m.hookInsert(doc);
} catch (err) {
2018-10-17 16:42:33 +00:00
console.log(`[db] Insert hook failed for ${type} ${doc._id}: ${err.message}`);
}
}
if (type === CHANGE_UPDATE && typeof m.hookUpdate === 'function') {
try {
await m.hookUpdate(doc);
} catch (err) {
2018-10-17 16:42:33 +00:00
console.log(`[db] Update hook failed for ${type} ${doc._id}: ${err.message}`);
}
}
}
});
for (const model of models.all()) {
if (typeof model.hookDatabaseInit === 'function') {
await model.hookDatabaseInit();
}
}
}
2016-07-16 07:22:08 +00:00
// ~~~~~~~~~~~~~~~~ //
// Change Listeners //
// ~~~~~~~~~~~~~~~~ //
let bufferingChanges = false;
let bufferChangesId = 1;
let changeBuffer = [];
let changeListeners = [];
2018-06-25 17:42:50 +00:00
export function onChange(callback: Function): void {
changeListeners.push(callback);
}
2018-06-25 17:42:50 +00:00
export function offChange(callback: Function): void {
changeListeners = changeListeners.filter(l => l !== callback);
}
/** buffers database changes and returns false if was already buffering */
2018-06-25 17:42:50 +00:00
export const bufferChanges = (database.bufferChanges = async function(
millis: number = 1000,
): Promise<number> {
if (db._empty) return _send('bufferChanges', ...arguments);
bufferingChanges = true;
setTimeout(database.flushChanges, millis);
return ++bufferChangesId;
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const flushChangesAsync = (database.flushChangesAsync = async function() {
process.nextTick(async () => {
await flushChanges();
});
2018-06-25 17:42:50 +00:00
});
export const flushChanges = (database.flushChanges = async function(id: number = 0) {
if (db._empty) return _send('flushChanges', ...arguments);
// Only flush if ID is 0 or the current flush ID is the same as passed
if (id !== 0 && bufferChangesId !== id) {
return;
}
bufferingChanges = false;
const changes = [...changeBuffer];
changeBuffer = [];
2016-09-22 19:44:28 +00:00
if (changes.length === 0) {
// No work to do
return;
}
// Notify local listeners too
for (const fn of changeListeners) {
await fn(changes);
}
// Notify remote listeners
const windows = electron.BrowserWindow.getAllWindows();
for (const window of windows) {
window.webContents.send('db.changes', changes);
}
2018-06-25 17:42:50 +00:00
});
2018-10-17 16:42:33 +00:00
async function notifyOfChange(event: string, doc: BaseModel, fromSync: boolean): Promise<void> {
changeBuffer.push([event, doc, fromSync]);
// Flush right away if we're not buffering
if (!bufferingChanges) {
await database.flushChanges();
}
2016-09-08 06:54:35 +00:00
}
// ~~~~~~~ //
// Helpers //
// ~~~~~~~ //
2018-06-25 17:42:50 +00:00
export const getMostRecentlyModified = (database.getMostRecentlyModified = async function(
2017-07-19 00:19:56 +00:00
type: string,
query: Object = {},
2017-07-19 01:55:47 +00:00
): Promise<BaseModel | null> {
if (db._empty) return _send('getMostRecentlyModified', ...arguments);
const docs = await database.findMostRecentlyModified(type, query, 1);
return docs.length ? docs[0] : null;
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const findMostRecentlyModified = (database.findMostRecentlyModified = async function(
2017-07-19 00:19:56 +00:00
type: string,
query: Object = {},
limit: number | null = null,
2017-07-19 01:55:47 +00:00
): Promise<Array<BaseModel>> {
if (db._empty) return _send('findMostRecentlyModified', ...arguments);
2016-09-08 06:54:35 +00:00
return new Promise(resolve => {
2018-06-25 17:42:50 +00:00
db[type]
.find(query)
.sort({ modified: -1 })
.limit(limit)
.exec(async (err, rawDocs) => {
if (err) {
console.warn('[db] Failed to find docs', err);
resolve([]);
return;
}
2018-06-25 17:42:50 +00:00
const docs = [];
for (const rawDoc of rawDocs) {
docs.push(await models.initModel(type, rawDoc));
}
2018-06-25 17:42:50 +00:00
resolve(docs);
});
});
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const find = (database.find = async function<T: BaseModel>(
2017-07-19 00:19:56 +00:00
type: string,
query: Object = {},
sort: Object = { created: 1 },
2017-07-19 01:55:47 +00:00
): Promise<Array<T>> {
if (db._empty) return _send('find', ...arguments);
return new Promise((resolve, reject) => {
2018-06-25 17:42:50 +00:00
db[type]
.find(query)
.sort(sort)
.exec(async (err, rawDocs) => {
if (err) {
return reject(err);
}
2018-06-25 17:42:50 +00:00
const docs = [];
for (const rawDoc of rawDocs) {
docs.push(await models.initModel(type, rawDoc));
}
2018-06-25 17:42:50 +00:00
resolve(docs);
});
});
2018-06-25 17:42:50 +00:00
});
2018-10-17 16:42:33 +00:00
export const all = (database.all = async function<T: BaseModel>(type: string): Promise<Array<T>> {
if (db._empty) return _send('all', ...arguments);
return database.find(type);
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const getWhere = (database.getWhere = async function<T: BaseModel>(
type: string,
query: Object,
): Promise<T | null> {
if (db._empty) return _send('getWhere', ...arguments);
const docs = await database.find(type, query);
return docs.length ? docs[0] : null;
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const get = (database.get = async function<T: BaseModel>(
type: string,
id: string,
): Promise<T | null> {
if (db._empty) return _send('get', ...arguments);
// Short circuit IDs used to represent nothing
if (!id || id === 'n/a') {
return null;
2017-07-19 01:55:47 +00:00
} else {
2018-06-25 17:42:50 +00:00
return database.getWhere(type, { _id: id });
}
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const count = (database.count = async function(
type: string,
query: Object = {},
): Promise<number> {
if (db._empty) return _send('count', ...arguments);
return new Promise((resolve, reject) => {
db[type].count(query, (err, count) => {
if (err) {
return reject(err);
}
2016-05-11 05:43:51 +00:00
resolve(count);
});
});
2018-06-25 17:42:50 +00:00
});
2016-04-16 23:24:57 +00:00
2018-06-25 17:42:50 +00:00
export const upsert = (database.upsert = async function(
doc: BaseModel,
fromSync: boolean = false,
): Promise<BaseModel> {
if (db._empty) return _send('upsert', ...arguments);
const existingDoc = await database.get(doc.type, doc._id);
if (existingDoc) {
return database.update(doc, fromSync);
} else {
return database.insert(doc, fromSync);
}
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const insert = (database.insert = async function<T: BaseModel>(
doc: T,
fromSync: boolean = false,
): Promise<T> {
if (db._empty) return _send('insert', ...arguments);
2017-09-13 06:11:49 +00:00
return new Promise(async (resolve, reject) => {
Version Control (beta) (#1439) * VCS proof of concept underway! * Stuff * Some things * Replace deprecated Electron makeSingleInstance * Rename `window` variables so not to be confused with window object * Don't unnecessarily update request when URL does not change * Regenerate package-lock * Fix tests + ESLint * Publish - insomnia-app@1.0.49 - insomnia-cookies@0.0.12 - insomnia-httpsnippet@1.16.18 - insomnia-importers@2.0.13 - insomnia-libcurl@0.0.23 - insomnia-prettify@0.1.7 - insomnia-url@0.1.6 - insomnia-xpath@1.0.9 - insomnia-plugin-base64@1.0.6 - insomnia-plugin-cookie-jar@1.0.8 - insomnia-plugin-core-themes@1.0.5 - insomnia-plugin-default-headers@1.1.9 - insomnia-plugin-file@1.0.7 - insomnia-plugin-hash@1.0.7 - insomnia-plugin-jsonpath@1.0.12 - insomnia-plugin-now@1.0.11 - insomnia-plugin-os@1.0.13 - insomnia-plugin-prompt@1.1.9 - insomnia-plugin-request@1.0.18 - insomnia-plugin-response@1.0.16 - insomnia-plugin-uuid@1.0.10 * Broken but w/e * Some tweaks * Big refactor. Create local snapshots and push done * POC merging and a lot of improvements * Lots of work done on initial UI/UX * Fix old tests * Atomic writes and size-based batches * Update StageEntry definition once again to be better * Factor out GraphQL query logic * Merge algorithm, history modal, other minor things * Fix test * Merge, checkout, revert w/ user changes now work * Force UI to refresh when switching branches changes active request * Rough draft pull() and some cleanup * E2EE stuff and some refactoring * Add ability to share project with team and fixed tests * VCS now created in root component and better remote project handling * Remove unused definition * Publish - insomnia-account@0.0.2 - insomnia-app@1.1.1 - insomnia-cookies@0.0.14 - insomnia-httpsnippet@1.16.20 - insomnia-importers@2.0.15 - insomnia-libcurl@0.0.25 - insomnia-prettify@0.1.9 - insomnia-sync@0.0.2 - insomnia-url@0.1.8 - insomnia-xpath@1.0.11 - insomnia-plugin-base64@1.0.8 - insomnia-plugin-cookie-jar@1.0.10 - insomnia-plugin-core-themes@1.0.7 - insomnia-plugin-file@1.0.9 - insomnia-plugin-hash@1.0.9 - insomnia-plugin-jsonpath@1.0.14 - insomnia-plugin-now@1.0.13 - insomnia-plugin-os@1.0.15 - insomnia-plugin-prompt@1.1.11 - insomnia-plugin-request@1.0.20 - insomnia-plugin-response@1.0.18 - insomnia-plugin-uuid@1.0.12 * Move some deps around * Fix Flow errors * Update package.json * Fix eslint errors * Fix tests * Update deps * bootstrap insomnia-sync * TRy fixing appveyor * Try something else * Bump lerna * try powershell * Try again * Fix imports * Fixed errors * sync types refactor * Show remote projects in workspace dropdown * Improved pulling of non-local workspaces * Loading indicators and some tweaks * Clean up sync staging modal * Some sync improvements: - No longer store stage - Upgrade Electron - Sync UI/UX improvements * Fix snyc tests * Upgraded deps and hot loader tweaks (it's broken for some reason) * Fix tests * Branches dialog, network refactoring, some tweaks * Fixed merging when other branch is empty * A bunch of small fixes from real testing * Fixed pull merge logic * Fix tests * Some bug fixes * A few small tweaks * Conflict resolution and other improvements * Fix tests * Add revert changes * Deal with duplicate projects per workspace * Some tweaks and accessibility improvements * Tooltip accessibility * Fix API endpoint * Fix tests * Remove jest dep from insomnia-importers
2019-04-18 00:50:03 +00:00
let docWithDefaults;
try {
docWithDefaults = await models.initModel(doc.type, doc);
} catch (err) {
return reject(err);
}
db[doc.type].insert(docWithDefaults, (err, newDoc) => {
if (err) {
return reject(err);
}
2016-06-18 21:02:27 +00:00
resolve(newDoc);
// NOTE: This needs to be after we resolve
notifyOfChange(CHANGE_INSERT, newDoc, fromSync);
});
});
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const update = (database.update = async function<T: BaseModel>(
doc: T,
fromSync: boolean = false,
): Promise<T> {
if (db._empty) return _send('update', ...arguments);
2017-09-13 06:11:49 +00:00
return new Promise(async (resolve, reject) => {
Version Control (beta) (#1439) * VCS proof of concept underway! * Stuff * Some things * Replace deprecated Electron makeSingleInstance * Rename `window` variables so not to be confused with window object * Don't unnecessarily update request when URL does not change * Regenerate package-lock * Fix tests + ESLint * Publish - insomnia-app@1.0.49 - insomnia-cookies@0.0.12 - insomnia-httpsnippet@1.16.18 - insomnia-importers@2.0.13 - insomnia-libcurl@0.0.23 - insomnia-prettify@0.1.7 - insomnia-url@0.1.6 - insomnia-xpath@1.0.9 - insomnia-plugin-base64@1.0.6 - insomnia-plugin-cookie-jar@1.0.8 - insomnia-plugin-core-themes@1.0.5 - insomnia-plugin-default-headers@1.1.9 - insomnia-plugin-file@1.0.7 - insomnia-plugin-hash@1.0.7 - insomnia-plugin-jsonpath@1.0.12 - insomnia-plugin-now@1.0.11 - insomnia-plugin-os@1.0.13 - insomnia-plugin-prompt@1.1.9 - insomnia-plugin-request@1.0.18 - insomnia-plugin-response@1.0.16 - insomnia-plugin-uuid@1.0.10 * Broken but w/e * Some tweaks * Big refactor. Create local snapshots and push done * POC merging and a lot of improvements * Lots of work done on initial UI/UX * Fix old tests * Atomic writes and size-based batches * Update StageEntry definition once again to be better * Factor out GraphQL query logic * Merge algorithm, history modal, other minor things * Fix test * Merge, checkout, revert w/ user changes now work * Force UI to refresh when switching branches changes active request * Rough draft pull() and some cleanup * E2EE stuff and some refactoring * Add ability to share project with team and fixed tests * VCS now created in root component and better remote project handling * Remove unused definition * Publish - insomnia-account@0.0.2 - insomnia-app@1.1.1 - insomnia-cookies@0.0.14 - insomnia-httpsnippet@1.16.20 - insomnia-importers@2.0.15 - insomnia-libcurl@0.0.25 - insomnia-prettify@0.1.9 - insomnia-sync@0.0.2 - insomnia-url@0.1.8 - insomnia-xpath@1.0.11 - insomnia-plugin-base64@1.0.8 - insomnia-plugin-cookie-jar@1.0.10 - insomnia-plugin-core-themes@1.0.7 - insomnia-plugin-file@1.0.9 - insomnia-plugin-hash@1.0.9 - insomnia-plugin-jsonpath@1.0.14 - insomnia-plugin-now@1.0.13 - insomnia-plugin-os@1.0.15 - insomnia-plugin-prompt@1.1.11 - insomnia-plugin-request@1.0.20 - insomnia-plugin-response@1.0.18 - insomnia-plugin-uuid@1.0.12 * Move some deps around * Fix Flow errors * Update package.json * Fix eslint errors * Fix tests * Update deps * bootstrap insomnia-sync * TRy fixing appveyor * Try something else * Bump lerna * try powershell * Try again * Fix imports * Fixed errors * sync types refactor * Show remote projects in workspace dropdown * Improved pulling of non-local workspaces * Loading indicators and some tweaks * Clean up sync staging modal * Some sync improvements: - No longer store stage - Upgrade Electron - Sync UI/UX improvements * Fix snyc tests * Upgraded deps and hot loader tweaks (it's broken for some reason) * Fix tests * Branches dialog, network refactoring, some tweaks * Fixed merging when other branch is empty * A bunch of small fixes from real testing * Fixed pull merge logic * Fix tests * Some bug fixes * A few small tweaks * Conflict resolution and other improvements * Fix tests * Add revert changes * Deal with duplicate projects per workspace * Some tweaks and accessibility improvements * Tooltip accessibility * Fix API endpoint * Fix tests * Remove jest dep from insomnia-importers
2019-04-18 00:50:03 +00:00
let docWithDefaults;
try {
docWithDefaults = await models.initModel(doc.type, doc);
} catch (err) {
return reject(err);
}
2018-06-25 17:42:50 +00:00
db[doc.type].update({ _id: docWithDefaults._id }, docWithDefaults, err => {
if (err) {
return reject(err);
}
resolve(docWithDefaults);
// NOTE: This needs to be after we resolve
notifyOfChange(CHANGE_UPDATE, docWithDefaults, fromSync);
});
});
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const remove = (database.remove = async function<T: BaseModel>(
doc: T,
fromSync: boolean = false,
): Promise<void> {
if (db._empty) return _send('remove', ...arguments);
const flushId = await database.bufferChanges();
const docs = await database.withDescendants(doc);
const docIds = docs.map(d => d._id);
const types = [...new Set(docs.map(d => d.type))];
2016-08-15 22:31:30 +00:00
// Don't really need to wait for this to be over;
2018-06-25 17:42:50 +00:00
types.map(t => db[t].remove({ _id: { $in: docIds } }, { multi: true }));
docs.map(d => notifyOfChange(CHANGE_REMOVE, d, fromSync));
await database.flushChanges(flushId);
});
/** Removes entries without removing their children */
export const unsafeRemove = (database.unsafeRemove = async function<T: BaseModel>(
doc: T,
fromSync: boolean = false,
): Promise<void> {
if (db._empty) return _send('unsafeRemove', ...arguments);
db[doc.type].remove({ _id: doc._id });
notifyOfChange(CHANGE_REMOVE, doc, fromSync);
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const removeWhere = (database.removeWhere = async function(
type: string,
query: Object,
): Promise<void> {
if (db._empty) return _send('removeWhere', ...arguments);
2016-04-16 23:24:57 +00:00
const flushId = await database.bufferChanges();
2017-07-17 18:20:38 +00:00
for (const doc of await database.find(type, query)) {
const docs = await database.withDescendants(doc);
2017-07-17 18:20:38 +00:00
const docIds = docs.map(d => d._id);
const types = [...new Set(docs.map(d => d.type))];
// Don't really need to wait for this to be over;
2018-06-25 17:42:50 +00:00
types.map(t => db[t].remove({ _id: { $in: docIds } }, { multi: true }));
2017-07-17 18:20:38 +00:00
2017-07-19 01:55:47 +00:00
docs.map(d => notifyOfChange(CHANGE_REMOVE, d, false));
2017-07-17 18:20:38 +00:00
}
await database.flushChanges(flushId);
2018-06-25 17:42:50 +00:00
});
Version Control (beta) (#1439) * VCS proof of concept underway! * Stuff * Some things * Replace deprecated Electron makeSingleInstance * Rename `window` variables so not to be confused with window object * Don't unnecessarily update request when URL does not change * Regenerate package-lock * Fix tests + ESLint * Publish - insomnia-app@1.0.49 - insomnia-cookies@0.0.12 - insomnia-httpsnippet@1.16.18 - insomnia-importers@2.0.13 - insomnia-libcurl@0.0.23 - insomnia-prettify@0.1.7 - insomnia-url@0.1.6 - insomnia-xpath@1.0.9 - insomnia-plugin-base64@1.0.6 - insomnia-plugin-cookie-jar@1.0.8 - insomnia-plugin-core-themes@1.0.5 - insomnia-plugin-default-headers@1.1.9 - insomnia-plugin-file@1.0.7 - insomnia-plugin-hash@1.0.7 - insomnia-plugin-jsonpath@1.0.12 - insomnia-plugin-now@1.0.11 - insomnia-plugin-os@1.0.13 - insomnia-plugin-prompt@1.1.9 - insomnia-plugin-request@1.0.18 - insomnia-plugin-response@1.0.16 - insomnia-plugin-uuid@1.0.10 * Broken but w/e * Some tweaks * Big refactor. Create local snapshots and push done * POC merging and a lot of improvements * Lots of work done on initial UI/UX * Fix old tests * Atomic writes and size-based batches * Update StageEntry definition once again to be better * Factor out GraphQL query logic * Merge algorithm, history modal, other minor things * Fix test * Merge, checkout, revert w/ user changes now work * Force UI to refresh when switching branches changes active request * Rough draft pull() and some cleanup * E2EE stuff and some refactoring * Add ability to share project with team and fixed tests * VCS now created in root component and better remote project handling * Remove unused definition * Publish - insomnia-account@0.0.2 - insomnia-app@1.1.1 - insomnia-cookies@0.0.14 - insomnia-httpsnippet@1.16.20 - insomnia-importers@2.0.15 - insomnia-libcurl@0.0.25 - insomnia-prettify@0.1.9 - insomnia-sync@0.0.2 - insomnia-url@0.1.8 - insomnia-xpath@1.0.11 - insomnia-plugin-base64@1.0.8 - insomnia-plugin-cookie-jar@1.0.10 - insomnia-plugin-core-themes@1.0.7 - insomnia-plugin-file@1.0.9 - insomnia-plugin-hash@1.0.9 - insomnia-plugin-jsonpath@1.0.14 - insomnia-plugin-now@1.0.13 - insomnia-plugin-os@1.0.15 - insomnia-plugin-prompt@1.1.11 - insomnia-plugin-request@1.0.20 - insomnia-plugin-response@1.0.18 - insomnia-plugin-uuid@1.0.12 * Move some deps around * Fix Flow errors * Update package.json * Fix eslint errors * Fix tests * Update deps * bootstrap insomnia-sync * TRy fixing appveyor * Try something else * Bump lerna * try powershell * Try again * Fix imports * Fixed errors * sync types refactor * Show remote projects in workspace dropdown * Improved pulling of non-local workspaces * Loading indicators and some tweaks * Clean up sync staging modal * Some sync improvements: - No longer store stage - Upgrade Electron - Sync UI/UX improvements * Fix snyc tests * Upgraded deps and hot loader tweaks (it's broken for some reason) * Fix tests * Branches dialog, network refactoring, some tweaks * Fixed merging when other branch is empty * A bunch of small fixes from real testing * Fixed pull merge logic * Fix tests * Some bug fixes * A few small tweaks * Conflict resolution and other improvements * Fix tests * Add revert changes * Deal with duplicate projects per workspace * Some tweaks and accessibility improvements * Tooltip accessibility * Fix API endpoint * Fix tests * Remove jest dep from insomnia-importers
2019-04-18 00:50:03 +00:00
export const batchModifyDocs = (database.batchModifyDocs = async function(operations: {
upsert: Array<Object>,
remove: Array<Object>,
}): Promise<void> {
if (db._empty) return _send('batchModifyDocs', ...arguments);
const flushId = await bufferChanges();
const promisesUpserted = [];
const promisesDeleted = [];
for (const doc: BaseModel of operations.upsert) {
promisesUpserted.push(upsert(doc, true));
}
for (const doc: BaseModel of operations.remove) {
promisesDeleted.push(unsafeRemove(doc, true));
}
// Perform from least to most dangerous
await Promise.all(promisesUpserted);
await Promise.all(promisesDeleted);
await flushChanges(flushId);
});
// ~~~~~~~~~~~~~~~~~~~ //
// DEFAULT MODEL STUFF //
// ~~~~~~~~~~~~~~~~~~~ //
2016-04-16 23:24:57 +00:00
2018-06-25 17:42:50 +00:00
export async function docUpdate<T: BaseModel>(
originalDoc: T,
...patches: Array<Object>
): Promise<T> {
const doc = await models.initModel(
originalDoc.type,
originalDoc,
// NOTE: This is before `patch` because we want `patch.modified` to win if it has it
2018-06-25 17:42:50 +00:00
{ modified: Date.now() },
...patches,
);
return database.update(doc);
}
2016-07-19 16:15:03 +00:00
2018-10-17 16:42:33 +00:00
export async function docCreate<T: BaseModel>(type: string, ...patches: Array<Object>): Promise<T> {
const doc = await models.initModel(
type,
...patches,
2016-04-18 04:39:15 +00:00
2016-08-15 22:31:30 +00:00
// Fields that the user can't touch
{ type: type },
);
2016-04-18 04:39:15 +00:00
return database.insert(doc);
}
2016-08-15 22:31:30 +00:00
// ~~~~~~~ //
// GENERAL //
// ~~~~~~~ //
2018-06-25 17:42:50 +00:00
export const withDescendants = (database.withDescendants = async function(
doc: BaseModel | null,
stopType: string | null = null,
): Promise<Array<BaseModel>> {
if (db._empty) return _send('withDescendants', ...arguments);
2016-08-15 22:31:30 +00:00
let docsToReturn = doc ? [doc] : [];
2018-10-17 16:42:33 +00:00
async function next(docs: Array<BaseModel | null>): Promise<Array<BaseModel>> {
let foundDocs = [];
for (const d of docs) {
if (stopType && d && d.type === stopType) {
continue;
}
const promises = [];
2016-11-10 01:15:27 +00:00
for (const type of allTypes()) {
2016-08-15 22:31:30 +00:00
// If the doc is null, we want to search for parentId === null
const parentId = d ? d._id : null;
promises.push(database.find(type, { parentId }));
}
for (const more of await Promise.all(promises)) {
foundDocs = [...foundDocs, ...more];
2016-08-15 22:31:30 +00:00
}
}
if (foundDocs.length === 0) {
// Didn't find anything. We're done
return docsToReturn;
}
2016-08-15 22:31:30 +00:00
// Continue searching for children
docsToReturn = [...docsToReturn, ...foundDocs];
return next(foundDocs);
}
2016-08-15 22:31:30 +00:00
return next([doc]);
2018-06-25 17:42:50 +00:00
});
2016-08-15 22:31:30 +00:00
2018-06-25 17:42:50 +00:00
export const withAncestors = (database.withAncestors = async function(
2017-07-19 01:55:47 +00:00
doc: BaseModel | null,
types: Array<string> = allTypes(),
2017-07-19 01:55:47 +00:00
): Promise<Array<BaseModel>> {
if (db._empty) return _send('withAncestors', ...arguments);
2017-07-19 01:55:47 +00:00
if (!doc) {
return [];
}
Sync Proof of Concept (#33) * Maybe working POC * Change to use remote url * Other URL too * Some logic * Got the push part working * Made some updates * Fix * Update * Add status code check * Stuff * Implemented new sync api * A bit more robust * Debounce changes * Change timeout * Some fixes * Remove .less * Better error handling * Fix base url * Support for created vs updated docs * Try silent * Silence removal too * Small fix after merge * Fix test * Stuff * Implement key generation algorithm * Tidy * stuff * A bunch of stuff for the new API * Integrated the session stuff * Stuff * Just started on encryption * Lots of updates to encryption * Finished createResourceGroup function * Full encryption/decryption working (I think) * Encrypt localstorage with sessionID * Some more * Some extra checks * Now uses separate DB. Still needs to be simplified a LOT * Fix deletion bug * Fixed unicode bug with encryption * Simplified and working * A bunch of polish * Some stuff * Removed some workspace meta properties * Migrated a few more meta properties * Small changes * Fix body scrolling and url cursor jumping * Removed duplication of webpack port * Remove workspaces reduces * Some small fixes * Added sync modal and opt-in setting * Good start to sync flow * Refactored modal footer css * Update sync status * Sync logger * A bit better logging * Fixed a bunch of sync-related bugs * Fixed signup form button * Gravatar component * Split sync modal into tabs * Tidying * Some more error handling * start sending 'user agent * Login/signup error handling * Use real UUIDs * Fixed tests * Remove unused function * Some extra checks * Moved cloud sync setting to about page * Some small changes * Some things
2016-10-21 17:20:36 +00:00
let docsToReturn = doc ? [doc] : [];
2018-06-25 17:42:50 +00:00
async function next(docs: Array<BaseModel>): Promise<Array<BaseModel>> {
Sync Proof of Concept (#33) * Maybe working POC * Change to use remote url * Other URL too * Some logic * Got the push part working * Made some updates * Fix * Update * Add status code check * Stuff * Implemented new sync api * A bit more robust * Debounce changes * Change timeout * Some fixes * Remove .less * Better error handling * Fix base url * Support for created vs updated docs * Try silent * Silence removal too * Small fix after merge * Fix test * Stuff * Implement key generation algorithm * Tidy * stuff * A bunch of stuff for the new API * Integrated the session stuff * Stuff * Just started on encryption * Lots of updates to encryption * Finished createResourceGroup function * Full encryption/decryption working (I think) * Encrypt localstorage with sessionID * Some more * Some extra checks * Now uses separate DB. Still needs to be simplified a LOT * Fix deletion bug * Fixed unicode bug with encryption * Simplified and working * A bunch of polish * Some stuff * Removed some workspace meta properties * Migrated a few more meta properties * Small changes * Fix body scrolling and url cursor jumping * Removed duplication of webpack port * Remove workspaces reduces * Some small fixes * Added sync modal and opt-in setting * Good start to sync flow * Refactored modal footer css * Update sync status * Sync logger * A bit better logging * Fixed a bunch of sync-related bugs * Fixed signup form button * Gravatar component * Split sync modal into tabs * Tidying * Some more error handling * start sending 'user agent * Login/signup error handling * Use real UUIDs * Fixed tests * Remove unused function * Some extra checks * Moved cloud sync setting to about page * Some small changes * Some things
2016-10-21 17:20:36 +00:00
let foundDocs = [];
2017-07-19 01:55:47 +00:00
for (const d: BaseModel of docs) {
for (const type of types) {
Sync Proof of Concept (#33) * Maybe working POC * Change to use remote url * Other URL too * Some logic * Got the push part working * Made some updates * Fix * Update * Add status code check * Stuff * Implemented new sync api * A bit more robust * Debounce changes * Change timeout * Some fixes * Remove .less * Better error handling * Fix base url * Support for created vs updated docs * Try silent * Silence removal too * Small fix after merge * Fix test * Stuff * Implement key generation algorithm * Tidy * stuff * A bunch of stuff for the new API * Integrated the session stuff * Stuff * Just started on encryption * Lots of updates to encryption * Finished createResourceGroup function * Full encryption/decryption working (I think) * Encrypt localstorage with sessionID * Some more * Some extra checks * Now uses separate DB. Still needs to be simplified a LOT * Fix deletion bug * Fixed unicode bug with encryption * Simplified and working * A bunch of polish * Some stuff * Removed some workspace meta properties * Migrated a few more meta properties * Small changes * Fix body scrolling and url cursor jumping * Removed duplication of webpack port * Remove workspaces reduces * Some small fixes * Added sync modal and opt-in setting * Good start to sync flow * Refactored modal footer css * Update sync status * Sync logger * A bit better logging * Fixed a bunch of sync-related bugs * Fixed signup form button * Gravatar component * Split sync modal into tabs * Tidying * Some more error handling * start sending 'user agent * Login/signup error handling * Use real UUIDs * Fixed tests * Remove unused function * Some extra checks * Moved cloud sync setting to about page * Some small changes * Some things
2016-10-21 17:20:36 +00:00
// If the doc is null, we want to search for parentId === null
const another = await database.get(type, d.parentId);
another && foundDocs.push(another);
Sync Proof of Concept (#33) * Maybe working POC * Change to use remote url * Other URL too * Some logic * Got the push part working * Made some updates * Fix * Update * Add status code check * Stuff * Implemented new sync api * A bit more robust * Debounce changes * Change timeout * Some fixes * Remove .less * Better error handling * Fix base url * Support for created vs updated docs * Try silent * Silence removal too * Small fix after merge * Fix test * Stuff * Implement key generation algorithm * Tidy * stuff * A bunch of stuff for the new API * Integrated the session stuff * Stuff * Just started on encryption * Lots of updates to encryption * Finished createResourceGroup function * Full encryption/decryption working (I think) * Encrypt localstorage with sessionID * Some more * Some extra checks * Now uses separate DB. Still needs to be simplified a LOT * Fix deletion bug * Fixed unicode bug with encryption * Simplified and working * A bunch of polish * Some stuff * Removed some workspace meta properties * Migrated a few more meta properties * Small changes * Fix body scrolling and url cursor jumping * Removed duplication of webpack port * Remove workspaces reduces * Some small fixes * Added sync modal and opt-in setting * Good start to sync flow * Refactored modal footer css * Update sync status * Sync logger * A bit better logging * Fixed a bunch of sync-related bugs * Fixed signup form button * Gravatar component * Split sync modal into tabs * Tidying * Some more error handling * start sending 'user agent * Login/signup error handling * Use real UUIDs * Fixed tests * Remove unused function * Some extra checks * Moved cloud sync setting to about page * Some small changes * Some things
2016-10-21 17:20:36 +00:00
}
}
if (foundDocs.length === 0) {
// Didn't find anything. We're done
return docsToReturn;
}
// Continue searching for children
docsToReturn = [...docsToReturn, ...foundDocs];
return next(foundDocs);
Sync Proof of Concept (#33) * Maybe working POC * Change to use remote url * Other URL too * Some logic * Got the push part working * Made some updates * Fix * Update * Add status code check * Stuff * Implemented new sync api * A bit more robust * Debounce changes * Change timeout * Some fixes * Remove .less * Better error handling * Fix base url * Support for created vs updated docs * Try silent * Silence removal too * Small fix after merge * Fix test * Stuff * Implement key generation algorithm * Tidy * stuff * A bunch of stuff for the new API * Integrated the session stuff * Stuff * Just started on encryption * Lots of updates to encryption * Finished createResourceGroup function * Full encryption/decryption working (I think) * Encrypt localstorage with sessionID * Some more * Some extra checks * Now uses separate DB. Still needs to be simplified a LOT * Fix deletion bug * Fixed unicode bug with encryption * Simplified and working * A bunch of polish * Some stuff * Removed some workspace meta properties * Migrated a few more meta properties * Small changes * Fix body scrolling and url cursor jumping * Removed duplication of webpack port * Remove workspaces reduces * Some small fixes * Added sync modal and opt-in setting * Good start to sync flow * Refactored modal footer css * Update sync status * Sync logger * A bit better logging * Fixed a bunch of sync-related bugs * Fixed signup form button * Gravatar component * Split sync modal into tabs * Tidying * Some more error handling * start sending 'user agent * Login/signup error handling * Use real UUIDs * Fixed tests * Remove unused function * Some extra checks * Moved cloud sync setting to about page * Some small changes * Some things
2016-10-21 17:20:36 +00:00
}
return next([doc]);
2018-06-25 17:42:50 +00:00
});
2018-06-25 17:42:50 +00:00
export const duplicate = (database.duplicate = async function<T: BaseModel>(
originalDoc: T,
patch: Object = {},
): Promise<T> {
if (db._empty) return _send('duplicate', ...arguments);
Sync Proof of Concept (#33) * Maybe working POC * Change to use remote url * Other URL too * Some logic * Got the push part working * Made some updates * Fix * Update * Add status code check * Stuff * Implemented new sync api * A bit more robust * Debounce changes * Change timeout * Some fixes * Remove .less * Better error handling * Fix base url * Support for created vs updated docs * Try silent * Silence removal too * Small fix after merge * Fix test * Stuff * Implement key generation algorithm * Tidy * stuff * A bunch of stuff for the new API * Integrated the session stuff * Stuff * Just started on encryption * Lots of updates to encryption * Finished createResourceGroup function * Full encryption/decryption working (I think) * Encrypt localstorage with sessionID * Some more * Some extra checks * Now uses separate DB. Still needs to be simplified a LOT * Fix deletion bug * Fixed unicode bug with encryption * Simplified and working * A bunch of polish * Some stuff * Removed some workspace meta properties * Migrated a few more meta properties * Small changes * Fix body scrolling and url cursor jumping * Removed duplication of webpack port * Remove workspaces reduces * Some small fixes * Added sync modal and opt-in setting * Good start to sync flow * Refactored modal footer css * Update sync status * Sync logger * A bit better logging * Fixed a bunch of sync-related bugs * Fixed signup form button * Gravatar component * Split sync modal into tabs * Tidying * Some more error handling * start sending 'user agent * Login/signup error handling * Use real UUIDs * Fixed tests * Remove unused function * Some extra checks * Moved cloud sync setting to about page * Some small changes * Some things
2016-10-21 17:20:36 +00:00
const flushId = await database.bufferChanges();
2016-08-15 22:31:30 +00:00
2018-06-25 17:42:50 +00:00
async function next<T: BaseModel>(docToCopy: T, patch: Object): Promise<T> {
2017-06-07 00:07:09 +00:00
// 1. Copy the doc
const newDoc = Object.assign({}, docToCopy, patch);
delete newDoc._id;
delete newDoc.created;
delete newDoc.modified;
2016-08-15 22:31:30 +00:00
const createdDoc = await docCreate(newDoc.type, newDoc);
2016-09-08 06:54:35 +00:00
2017-06-07 00:07:09 +00:00
// 2. Get all the children
for (const type of allTypes()) {
// Note: We never want to duplicate a response
if (!models.canDuplicate(type)) {
continue;
}
2017-06-07 00:07:09 +00:00
const parentId = docToCopy._id;
2018-06-25 17:42:50 +00:00
const children = await database.find(type, { parentId });
2017-06-07 00:07:09 +00:00
for (const doc of children) {
2018-06-25 17:42:50 +00:00
await next(doc, { parentId: createdDoc._id });
2017-06-07 00:07:09 +00:00
}
}
2016-09-08 06:54:35 +00:00
2017-06-07 00:07:09 +00:00
return createdDoc;
2016-10-21 20:00:31 +00:00
}
2016-09-08 06:54:35 +00:00
2017-06-07 00:07:09 +00:00
const createdDoc = await next(originalDoc, patch);
await database.flushChanges(flushId);
2017-06-07 00:07:09 +00:00
return createdDoc;
2018-06-25 17:42:50 +00:00
});
// ~~~~~~~ //
// Helpers //
// ~~~~~~~ //
2018-06-25 17:42:50 +00:00
async function _send<T>(fnName: string, ...args: Array<any>): Promise<T> {
return new Promise((resolve, reject) => {
const replyChannel = `db.fn.reply:${uuid.v4()}`;
electron.ipcRenderer.send('db.fn', fnName, replyChannel, ...args);
Version Control (beta) (#1439) * VCS proof of concept underway! * Stuff * Some things * Replace deprecated Electron makeSingleInstance * Rename `window` variables so not to be confused with window object * Don't unnecessarily update request when URL does not change * Regenerate package-lock * Fix tests + ESLint * Publish - insomnia-app@1.0.49 - insomnia-cookies@0.0.12 - insomnia-httpsnippet@1.16.18 - insomnia-importers@2.0.13 - insomnia-libcurl@0.0.23 - insomnia-prettify@0.1.7 - insomnia-url@0.1.6 - insomnia-xpath@1.0.9 - insomnia-plugin-base64@1.0.6 - insomnia-plugin-cookie-jar@1.0.8 - insomnia-plugin-core-themes@1.0.5 - insomnia-plugin-default-headers@1.1.9 - insomnia-plugin-file@1.0.7 - insomnia-plugin-hash@1.0.7 - insomnia-plugin-jsonpath@1.0.12 - insomnia-plugin-now@1.0.11 - insomnia-plugin-os@1.0.13 - insomnia-plugin-prompt@1.1.9 - insomnia-plugin-request@1.0.18 - insomnia-plugin-response@1.0.16 - insomnia-plugin-uuid@1.0.10 * Broken but w/e * Some tweaks * Big refactor. Create local snapshots and push done * POC merging and a lot of improvements * Lots of work done on initial UI/UX * Fix old tests * Atomic writes and size-based batches * Update StageEntry definition once again to be better * Factor out GraphQL query logic * Merge algorithm, history modal, other minor things * Fix test * Merge, checkout, revert w/ user changes now work * Force UI to refresh when switching branches changes active request * Rough draft pull() and some cleanup * E2EE stuff and some refactoring * Add ability to share project with team and fixed tests * VCS now created in root component and better remote project handling * Remove unused definition * Publish - insomnia-account@0.0.2 - insomnia-app@1.1.1 - insomnia-cookies@0.0.14 - insomnia-httpsnippet@1.16.20 - insomnia-importers@2.0.15 - insomnia-libcurl@0.0.25 - insomnia-prettify@0.1.9 - insomnia-sync@0.0.2 - insomnia-url@0.1.8 - insomnia-xpath@1.0.11 - insomnia-plugin-base64@1.0.8 - insomnia-plugin-cookie-jar@1.0.10 - insomnia-plugin-core-themes@1.0.7 - insomnia-plugin-file@1.0.9 - insomnia-plugin-hash@1.0.9 - insomnia-plugin-jsonpath@1.0.14 - insomnia-plugin-now@1.0.13 - insomnia-plugin-os@1.0.15 - insomnia-plugin-prompt@1.1.11 - insomnia-plugin-request@1.0.20 - insomnia-plugin-response@1.0.18 - insomnia-plugin-uuid@1.0.12 * Move some deps around * Fix Flow errors * Update package.json * Fix eslint errors * Fix tests * Update deps * bootstrap insomnia-sync * TRy fixing appveyor * Try something else * Bump lerna * try powershell * Try again * Fix imports * Fixed errors * sync types refactor * Show remote projects in workspace dropdown * Improved pulling of non-local workspaces * Loading indicators and some tweaks * Clean up sync staging modal * Some sync improvements: - No longer store stage - Upgrade Electron - Sync UI/UX improvements * Fix snyc tests * Upgraded deps and hot loader tweaks (it's broken for some reason) * Fix tests * Branches dialog, network refactoring, some tweaks * Fixed merging when other branch is empty * A bunch of small fixes from real testing * Fixed pull merge logic * Fix tests * Some bug fixes * A few small tweaks * Conflict resolution and other improvements * Fix tests * Add revert changes * Deal with duplicate projects per workspace * Some tweaks and accessibility improvements * Tooltip accessibility * Fix API endpoint * Fix tests * Remove jest dep from insomnia-importers
2019-04-18 00:50:03 +00:00
electron.ipcRenderer.once(replyChannel, (e, err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}
/**
* Run various database repair scripts
*/
2018-06-25 17:42:50 +00:00
export async function _repairDatabase() {
console.log(`[fix] Running database repairs`);
for (const workspace of await find(models.workspace.type)) {
await _repairBaseEnvironments(workspace);
await _fixMultipleCookieJars(workspace);
}
}
/**
* This function repairs workspaces that have multiple base environments. Since a workspace
* can only have one, this function walks over all base environments, merges the data, and
* moves all children as well.
*/
2018-06-25 17:42:50 +00:00
async function _repairBaseEnvironments(workspace) {
const baseEnvironments = await find(models.environment.type, {
parentId: workspace._id,
2018-06-25 17:42:50 +00:00
});
// Nothing to do here
if (baseEnvironments.length <= 1) {
return;
}
const chosenBase = baseEnvironments[0];
for (const baseEnvironment of baseEnvironments) {
if (baseEnvironment._id === chosenBase._id) {
continue;
}
chosenBase.data = Object.assign(baseEnvironment.data, chosenBase.data);
2018-06-25 17:42:50 +00:00
const subEnvironments = await find(models.environment.type, {
parentId: baseEnvironment._id,
2018-06-25 17:42:50 +00:00
});
for (const subEnvironment of subEnvironments) {
2018-06-25 17:42:50 +00:00
await docUpdate(subEnvironment, { parentId: chosenBase._id });
}
// Remove unnecessary base env
await remove(baseEnvironment);
}
// Update remaining base env
await update(chosenBase);
2018-10-17 16:42:33 +00:00
console.log(`[fix] Merged ${baseEnvironments.length} base environments under ${workspace.name}`);
}
/**
* This function repairs workspaces that have multiple cookie jars. Since a workspace
* can only have one, this function walks over all jars and merges them and their cookies
* together.
*/
2018-06-25 17:42:50 +00:00
async function _fixMultipleCookieJars(workspace) {
const cookieJars = await find(models.cookieJar.type, {
parentId: workspace._id,
2018-06-25 17:42:50 +00:00
});
// Nothing to do here
if (cookieJars.length <= 1) {
return;
}
const chosenJar = cookieJars[0];
for (const cookieJar of cookieJars) {
if (cookieJar._id === chosenJar._id) {
continue;
}
for (const cookie of cookieJar.cookies) {
if (chosenJar.cookies.find(c => c.id === cookie.id)) {
continue;
}
chosenJar.cookies.push(cookie);
}
// Remove unnecessary jar
await remove(cookieJar);
}
// Update remaining jar
await update(chosenJar);
2018-10-17 16:42:33 +00:00
console.log(`[fix] Merged ${cookieJars.length} cookie jars under ${workspace.name}`);
}