Async model migrations

This commit is contained in:
Gregory Schier committed 2017-09-13 08:11:49 +02:00
1 parent fe7781998b
commit a20ea65c4c
13 files changed
+71 -64

No files matched your search

+2 -1
View File
@@ -19,7 +19,8 @@ describe('exportHarWithRequest()', () => {
lastAccessed: new Date('2096-10-05T04:40:49.505Z')
}];
await models.cookieJar.create({
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspace._id);
await models.cookieJar.update(cookieJar, {
parentId: workspace._id,
cookies
});
+5 -4
View File
@@ -8,7 +8,7 @@ describe('export()', () => {
it('succeed with username and password', async () => {
const w = await models.workspace.create({name: 'Workspace'});
const r1 = await models.request.create({name: 'Request', parentId: w._id});
const eBase = await models.environment.create({name: 'Base', parentId: w._id});
const eBase = await models.environment.getOrCreateForWorkspace(w);
const ePub = await models.environment.create({name: 'Public', parentId: eBase._id});
await models.environment.create({name: 'Private', isPrivate: true, parentId: eBase._id});
@@ -21,8 +21,9 @@ describe('export()', () => {
expect(data.__export_source).toBe(`insomnia.desktop.app:v${getAppVersion()}`);
expect(data.resources[0]._id).toBe(w._id);
expect(data.resources[1]._id).toBe(eBase._id);
expect(data.resources[2]._id).toBe(r1._id);
expect(data.resources[3]._id).toBe(ePub._id);
expect(data.resources.length).toBe(4);
expect(data.resources[2]._id).toBe('jar_dd2ccc1a2745477a881a9e8ef9d42403');
expect(data.resources[3]._id).toBe(r1._id);
expect(data.resources[4]._id).toBe(ePub._id);
expect(data.resources.length).toBe(5);
});
});
+18 -16
View File
@@ -155,16 +155,17 @@ export function findMostRecentlyModified (
limit: number | null = null
): Promise<Array<BaseModel>> {
return new Promise(resolve => {
db[type].find(query).sort({modified: -1}).limit(limit).exec((err, rawDocs) => {
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;
}
const docs = rawDocs.map(rawDoc => {
return initModel(type, rawDoc);
});
const docs = [];
for (const rawDoc of rawDocs) {
docs.push(await initModel(type, rawDoc));
}
resolve(docs);
});
@@ -177,14 +178,15 @@ export function find<T: BaseModel> (
sort: Object = {created: 1}
): Promise<Array<T>> {
return new Promise((resolve, reject) => {
db[type].find(query).sort(sort).exec((err, rawDocs) => {
db[type].find(query).sort(sort).exec(async (err, rawDocs) => {
if (err) {
return reject(err);
}
const docs = rawDocs.map(rawDoc => {
return initModel(type, rawDoc);
});
const docs = [];
for (const rawDoc of rawDocs) {
docs.push(await initModel(type, rawDoc));
}
resolve(docs);
});
@@ -231,8 +233,8 @@ export async function upsert (doc: BaseModel, fromSync: boolean = false): Promis
}
export function insert<T: BaseModel> (doc: T, fromSync: boolean = false): Promise<T> {
return new Promise((resolve, reject) => {
const docWithDefaults = initModel(doc.type, doc);
return new Promise(async (resolve, reject) => {
const docWithDefaults = await initModel(doc.type, doc);
db[doc.type].insert(docWithDefaults, (err, newDoc) => {
if (err) {
return reject(err);
@@ -245,8 +247,8 @@ export function insert<T: BaseModel> (doc: T, fromSync: boolean = false): Promis
}
export function update<T: BaseModel> (doc: T, fromSync: boolean = false): Promise<T> {
return new Promise((resolve, reject) => {
const docWithDefaults = initModel(doc.type, doc);
return new Promise(async (resolve, reject) => {
const docWithDefaults = await initModel(doc.type, doc);
db[doc.type].update({_id: docWithDefaults._id}, docWithDefaults, err => {
if (err) {
return reject(err);
@@ -295,8 +297,8 @@ export async function removeWhere (type: string, query: Object): Promise<void> {
// DEFAULT MODEL STUFF //
// ~~~~~~~~~~~~~~~~~~~ //
export function docUpdate<T: BaseModel> (originalDoc: T, patch: Object = {}): Promise<T> {
const doc = initModel(
export async function docUpdate<T: BaseModel> (originalDoc: T, patch: Object = {}): Promise<T> {
const doc = await initModel(
originalDoc.type,
originalDoc,
@@ -309,8 +311,8 @@ export function docUpdate<T: BaseModel> (originalDoc: T, patch: Object = {}): Pr
return update(doc);
}
export function docCreate<T: BaseModel> (type: string, ...patches: Array<Object>): Promise<T> {
const doc = initModel(
export async function docCreate<T: BaseModel> (type: string, ...patches: Array<Object>): Promise<T> {
const doc = await initModel(
type,
...patches,
+2 -2
View File
@@ -253,7 +253,7 @@ describe('migrate()', () => {
expect(models.request.migrate(noBody)).toEqual(expected2);
});
it('migrates from initModel()', () => {
it('migrates from initModel()', async () => {
Date.now = jest.fn().mockReturnValue(1478795580200);
const original = {
@@ -283,7 +283,7 @@ describe('migrate()', () => {
settingEncodeUrl: true
};
const migrated = models.initModel(models.request.type, original);
const migrated = await models.initModel(models.request.type, original);
expect(migrated).toEqual(expected);
});
});
+4 -4
View File
@@ -13,7 +13,7 @@ describe('migrate()', () => {
it('migrates utf8 body correctly', async () => {
const initialModel = {body: 'hello world!', encoding: 'utf8'};
const newModel = models.initModel(models.response.type, initialModel);
const newModel = await models.initModel(models.response.type, initialModel);
const expectedBodyPath = path.join(
electron.remote.app.getPath('userData'),
`responses/fc3ff98e8c6a0d3087d515c0473f8677.zip`
@@ -32,7 +32,7 @@ describe('migrate()', () => {
it('migrates base64 body correctly', async () => {
const initialModel = {body: 'aGVsbG8gd29ybGQh', encoding: 'base64'};
const newModel = models.initModel(models.response.type, initialModel);
const newModel = await models.initModel(models.response.type, initialModel);
jest.runAllTimers();
const expectedBodyPath = path.join(
electron.remote.app.getPath('userData'),
@@ -52,7 +52,7 @@ describe('migrate()', () => {
it('migrates empty body', async () => {
const initialModel = {body: ''};
const newModel = models.initModel(models.response.type, initialModel);
const newModel = await models.initModel(models.response.type, initialModel);
jest.runAllTimers();
jest.runAllTimers();
@@ -74,7 +74,7 @@ describe('migrate()', () => {
it('does not migrate body again', async () => {
const initialModel = {bodyPath: '/foo/bar'};
const newModel = models.initModel(models.response.type, initialModel);
const newModel = await models.initModel(models.response.type, initialModel);
// Should have stripped these
expect(newModel.body).toBeUndefined();
+7 -3
View File
@@ -33,14 +33,14 @@ export function findByParentId (parentId) {
return db.find(type, {parentId});
}
export async function getOrCreateForWorkspace (workspace) {
export async function getOrCreateForWorkspaceId (workspaceId) {
let environment = await db.getWhere(type, {
parentId: workspace._id
parentId: workspaceId
});
if (!environment) {
environment = await create({
parentId: workspace._id,
parentId: workspaceId,
name: 'Base Environment'
});
}
@@ -48,6 +48,10 @@ export async function getOrCreateForWorkspace (workspace) {
return environment;
}
export async function getOrCreateForWorkspace (workspace) {
return getOrCreateForWorkspaceId(workspace._id);
}
export function getById (id) {
return db.get(type, id);
}
+5 -5
View File
@@ -82,7 +82,7 @@ export function getModelName (type: string, count: number = 1) {
}
}
export function initModel (type: string, ...sources: Array<Object>) {
export async function initModel <T: BaseModel> (type: string, ...sources: Array<Object>): Promise<T> {
const model = getModel(type);
if (!model) {
@@ -108,14 +108,14 @@ export function initModel (type: string, ...sources: Array<Object>) {
// Migrate the model
// NOTE: Do migration before pruning because we might need to look at those fields
model.migrate(fullObject);
const migratedDoc = await model.migrate(fullObject);
// Prune extra keys from doc
for (const key of Object.keys(fullObject)) {
for (const key of Object.keys(migratedDoc)) {
if (!objectDefaults.hasOwnProperty(key)) {
delete fullObject[key];
delete migratedDoc[key];
}
}
return fullObject;
return migratedDoc;
}
+7 -10
View File
@@ -32,7 +32,7 @@ export function init () {
};
}
export function migrate (doc: Object) {
export async function migrate (doc: Object) {
// There was a bug on import that would set this to the current workspace ID.
// Let's remove it here so that nothing bad happens.
if (doc.parentId !== null) {
@@ -40,6 +40,10 @@ export function migrate (doc: Object) {
process.nextTick(() => update(doc, {parentId: null}));
}
// Ensure child dependencies exist
await models.cookieJar.getOrCreateForParentId(doc._id);
await models.environment.getOrCreateForWorkspaceId(doc._id);
return doc;
}
@@ -47,15 +51,8 @@ export function getById (id: string): Promise<Workspace | null> {
return db.get(type, id);
}
export async function create (patch: Object = {}): Promise<Workspace> {
const workspace = await db.docCreate(type, patch);
// Make sure CookieJars and environments exist for all workspaces
// TODO: Find a better place to do this
await models.cookieJar.getOrCreateForParentId(workspace._id);
await models.environment.getOrCreateForWorkspace(workspace);
return workspace;
export function create (patch: Object = {}): Promise<Workspace> {
return db.docCreate(type, patch);
}
export async function all (): Promise<Array<Workspace>> {
+2 -1
View File
@@ -31,7 +31,8 @@ describe('actuallySend()', () => {
lastAccessed: new Date('2096-10-05T04:40:49.505Z')
}];
await models.cookieJar.create({
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspace._id);
await models.cookieJar.update(cookieJar, {
parentId: workspace._id,
cookies
});
+7 -9
View File
@@ -248,8 +248,6 @@ describe('Integration tests for creating Resources and pushing', () => {
await models.request.create({_id: 'req_1', name: 'Request 1', parentId: 'wrk_1'});
await models.request.create({_id: 'req_2', name: 'Request 2', parentId: 'wrk_1'});
await models.request.create({_id: 'req_3', name: 'Request 3', parentId: 'wrk_1'});
await models.cookieJar.create({_id: 'jar_1', name: 'Jar 1', parentId: 'wrk_1'});
await models.environment.create({_id: 'env_1', name: 'Env 1', parentId: 'wrk_1'});
await models.environment.create({_id: 'env_2', name: 'Env Prv', parentId: 'wrk_1', isPrivate: true});
// Flush changes just to be sure they won't affect our tests
@@ -259,8 +257,8 @@ describe('Integration tests for creating Resources and pushing', () => {
// Assert that all our new models were created
expect((await models.workspace.all()).length).toBe(2);
expect((await models.request.all()).length).toBe(3);
expect((await models.environment.all()).length).toBe(2);
expect((await models.cookieJar.all()).length).toBe(1);
expect((await models.environment.all()).length).toBe(3);
expect((await models.cookieJar.all()).length).toBe(2);
// Assert that initializing sync will create the initial resources
expect((await syncStorage.allConfigs()).length).toBe(0);
@@ -269,7 +267,7 @@ describe('Integration tests for creating Resources and pushing', () => {
jest.runOnlyPendingTimers();
await promise;
expect((await syncStorage.allConfigs()).length).toBe(2);
expect((await syncStorage.allResources()).length).toBe(7);
expect((await syncStorage.allResources()).length).toBe(9);
// Mark all configs as auto sync
const configs = await syncStorage.allConfigs();
@@ -304,12 +302,12 @@ describe('Integration tests for creating Resources and pushing', () => {
// Assert
expect((await syncStorage.allConfigs()).length).toBe(2);
expect((await syncStorage.allResources()).length).toBe(8);
expect((await syncStorage.allResources()).length).toBe(10);
expect(_decryptResource(resource).url).toBe('https://google.com');
expect(resource.removed).toBe(false);
expect(session.syncPush.mock.calls.length).toBe(1);
expect(session.syncPush.mock.calls[0][0].length).toBe(8);
expect(session.syncPush.mock.calls[0][0].length).toBe(10);
expect(session.syncPull.mock.calls).toEqual([]);
});
@@ -368,7 +366,7 @@ describe('Integration tests for creating Resources and pushing', () => {
expect(resource.removed).toBe(false);
expect(session.syncPush.mock.calls.length).toBe(1);
expect(session.syncPush.mock.calls[0][0].length).toBe(7);
expect(session.syncPush.mock.calls[0][0].length).toBe(9);
expect(session.syncPull.mock.calls).toEqual([]);
});
@@ -391,7 +389,7 @@ describe('Integration tests for creating Resources and pushing', () => {
expect(updatedResource.removed).toBe(true);
expect(session.syncPush.mock.calls.length).toBe(1);
expect(session.syncPush.mock.calls[0][0].length).toBe(7);
expect(session.syncPush.mock.calls[0][0].length).toBe(9);
expect(session.syncPull.mock.calls).toEqual([]);
});
@@ -1,5 +1,6 @@
// @flow
import type {Request} from '../../../../models/request';
import classnames from 'classnames';
import {newBodyRaw} from '../../../../models/request';
import React from 'react';
import autobind from 'autobind-decorator';
@@ -228,7 +229,7 @@ class GraphQLEditor extends React.PureComponent {
}
return (
<div className="txt-sm super-faint italic pad-sm inline-block">
<div className="txt-sm super-faint italic pad-sm no-pad-right inline-block">
{message}
</div>
);
@@ -251,7 +252,8 @@ class GraphQLEditor extends React.PureComponent {
schemaFetchError,
hideSchemaFetchErrors,
variablesSyntaxError,
forceRefreshKey
forceRefreshKey,
schemaIsFetching
} = this.state;
const {
@@ -294,13 +296,10 @@ class GraphQLEditor extends React.PureComponent {
)}
</div>
<div className="graphql-editor__schema-notice">
<button
className="icon pad-left-sm pad-top-sm pad-bottom-sm"
onClick={this._handleRefreshSchema}
>
<i className="fa fa-refresh" />
</button>
{this.renderSchemaFetchMessage()}
<button className={classnames('icon space-left', {'fa-spin': schemaIsFetching})} onClick={this._handleRefreshSchema}>
<i className="fa fa-refresh"/>
</button>
</div>
<h2 className="no-margin pad-left-sm pad-top-sm pad-bottom-sm">
Query Variables <HelpTooltip>Variables to use in GraphQL query <br/>(JSON
@@ -37,7 +37,7 @@ class RequestCreateModal extends PureComponent {
e.preventDefault();
const {parentId, selectedContentType, selectedMethod} = this.state;
const request = models.initModel(models.request.type, {
const request = await models.initModel(models.request.type, {
parentId,
name: this._input.value,
method: selectedMethod
+4
View File
@@ -526,6 +526,10 @@ i.fa:not(.fa--skinny) {
padding-bottom: 0;
}
.no-pad-right {
padding-right: 0;
}
.no-pad-left {
padding-left: 0;
}