mirror of
https://github.com/Kong/insomnia.git
synced 2026-10-27 17:19:42 -04:00
Handle duplicate env error / unique key constraint issue (#5674)
* pretty sure this will help * replace all the other ensure childrens * revert PR 4378 * ?fix? test and lint * fix lint Co-authored-by: Filipe Freire <livrofubia@gmail.com>
This commit is contained in:
1 parent
9d1873bfb3
commit
fc51f7a3cb
10 files changed
+22
-244
No files matched your search
@@ -1,70 +0,0 @@
|
||||
_type: export
|
||||
__export_format: 4
|
||||
__export_date: 2022-11-29T16:27:19.066Z
|
||||
__export_source: insomnia.desktop.app:v2022.7.0-beta.5
|
||||
resources:
|
||||
- _id: req_123
|
||||
parentId: wrk_123
|
||||
modified: 1669739211182
|
||||
created: 1669739179867
|
||||
url: mockbin.org/request/any/{{ _.base }}/{{ _.sub }}
|
||||
name: New Request
|
||||
description: ""
|
||||
method: GET
|
||||
body: {}
|
||||
parameters: []
|
||||
headers: []
|
||||
authentication: {}
|
||||
metaSortKey: -1669739179868
|
||||
isPrivate: false
|
||||
settingStoreCookies: true
|
||||
settingSendCookies: true
|
||||
settingDisableRenderRequestBody: false
|
||||
settingEncodeUrl: true
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
||||
_type: request
|
||||
- _id: wrk_123
|
||||
parentId: null
|
||||
modified: 1669739177487
|
||||
created: 1669739177487
|
||||
name: Example
|
||||
description: ""
|
||||
scope: collection
|
||||
_type: workspace
|
||||
- _id: env_123_from_export
|
||||
parentId: wrk_123
|
||||
modified: 1669739193740
|
||||
created: 1669739177493
|
||||
name: Base Environment
|
||||
data:
|
||||
base: 123
|
||||
dataPropertyOrder:
|
||||
"&":
|
||||
- base
|
||||
color: null
|
||||
isPrivate: false
|
||||
metaSortKey: 1669739177493
|
||||
_type: environment
|
||||
- _id: spc_5c1a165d02d34d228374d37566154a4a
|
||||
parentId: wrk_123
|
||||
modified: 1669739177487
|
||||
created: 1669739177487
|
||||
fileName: Example
|
||||
contents: ""
|
||||
contentType: yaml
|
||||
_type: api_spec
|
||||
- _id: env_sub123
|
||||
parentId: env_123_from_export
|
||||
modified: 1669739204645
|
||||
created: 1669739194224
|
||||
name: sub
|
||||
data:
|
||||
sub: 456
|
||||
dataPropertyOrder:
|
||||
"&":
|
||||
- sub
|
||||
color: null
|
||||
isPrivate: false
|
||||
metaSortKey: 1669739194224
|
||||
_type: environment
|
||||
@@ -3,7 +3,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { globalBeforeEach } from '../../__jest__/before-each';
|
||||
import { apiSpec, environment, request, requestGroup, workspace } from '../../models';
|
||||
import { apiSpec, request, requestGroup, workspace } from '../../models';
|
||||
import { DEFAULT_PROJECT_ID } from '../../models/project';
|
||||
import * as importUtil from '../import';
|
||||
|
||||
@@ -199,32 +199,4 @@ describe('importRaw()', () => {
|
||||
expect(createdApiSpec?.contents).toContain('openapi: \'3.0.2\'');
|
||||
});
|
||||
|
||||
it('should not leave dangling environments when reimporting a collection', async () => {
|
||||
const fixturePath = path.join(__dirname, '..', '__fixtures__', 'insomnia', 'insomnia-example-input.yaml');
|
||||
const rawFixture = fs.readFileSync(fixturePath, 'utf8').toString();
|
||||
|
||||
const existingWorkspace = await workspace.create({ scope: 'collection', _id: 'wrk_123' });
|
||||
|
||||
// Simulate pre-existing base and sub environment
|
||||
await environment.create({ parentId: 'wrk_123', _id: 'env_123' });
|
||||
await environment.create({ parentId: 'env_123', _id: 'env_sub123' });
|
||||
|
||||
const importConfig: importUtil.ImportRawConfig = {
|
||||
getWorkspaceId: () => existingWorkspace._id,
|
||||
getProjectId: async () => DEFAULT_PROJECT_ID,
|
||||
getWorkspaceScope: () => 'collection',
|
||||
};
|
||||
|
||||
await importUtil.importRaw(
|
||||
rawFixture,
|
||||
importConfig
|
||||
);
|
||||
|
||||
const totalEnvironments = await environment.all();
|
||||
const baseEnvironmentsFound = await environment.findByParentId('wrk_123');
|
||||
const subEnvironmentsFound = await environment.findByParentId('env_123');
|
||||
expect(totalEnvironments).toHaveLength(2);
|
||||
expect(baseEnvironmentsFound).toHaveLength(1);
|
||||
expect(subEnvironmentsFound).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -15,7 +15,6 @@ import { convert, ConvertResultType } from '../utils/importers/convert';
|
||||
import {
|
||||
BASE_ENVIRONMENT_ID_KEY,
|
||||
CONTENT_TYPE_GRAPHQL,
|
||||
EXPORT_TYPE_ENVIRONMENT,
|
||||
EXPORT_TYPE_WORKSPACE,
|
||||
WORKSPACE_ID_KEY,
|
||||
} from './constants';
|
||||
@@ -190,15 +189,6 @@ export async function importRaw(
|
||||
resource.parentId = WORKSPACE_ID_KEY;
|
||||
}
|
||||
|
||||
// Always generate base environment id, ensuring to not create another one
|
||||
if (resource._type === EXPORT_TYPE_ENVIRONMENT) {
|
||||
if (resource.parentId === WORKSPACE_ID_KEY || resource.parentId.match(`${models.workspace.prefix}_\w*`)) {
|
||||
resource._id = BASE_ENVIRONMENT_ID_KEY;
|
||||
} else {
|
||||
resource.parentId = BASE_ENVIRONMENT_ID_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace ID placeholders (eg. __WORKSPACE_ID__) with generated values
|
||||
for (const key of Object.keys(generatedIds)) {
|
||||
const { parentId, _id } = resource;
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { beforeEach, describe, expect, it } from '@jest/globals';
|
||||
|
||||
import { globalBeforeEach } from '../../__jest__/before-each';
|
||||
import { database } from '../../common/database';
|
||||
import { ApiSpec } from '../api-spec';
|
||||
import { CookieJar } from '../cookie-jar';
|
||||
import { Environment } from '../environment';
|
||||
import * as models from '../index';
|
||||
import { WorkspaceScopeKeys } from '../workspace';
|
||||
import { WorkspaceMeta } from '../workspace-meta';
|
||||
|
||||
describe('migrate()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
@@ -120,24 +115,3 @@ describe('migrate()', () => {
|
||||
expect(collectionW.scope).toBe(WorkspaceScopeKeys.collection);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ensureChildren()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
|
||||
it('creates children for workspace', async () => {
|
||||
const workspace = await models.workspace.create();
|
||||
await models.workspace.ensureChildren(workspace);
|
||||
|
||||
const descendents = await database.withDescendants(workspace);
|
||||
|
||||
expect(descendents).toHaveLength(5);
|
||||
expect(descendents).toStrictEqual(expect.arrayContaining([
|
||||
workspace,
|
||||
// ApiSpec is created as part of migration
|
||||
expect.objectContaining<Partial<ApiSpec>>({ parentId: workspace._id, type: models.apiSpec.type }),
|
||||
expect.objectContaining<Partial<Environment>>({ parentId: workspace._id, type: models.environment.type }),
|
||||
expect.objectContaining<Partial<CookieJar>>({ parentId: workspace._id, type: models.cookieJar.type }),
|
||||
expect.objectContaining<Partial<WorkspaceMeta>>({ parentId: workspace._id, type: models.workspaceMeta.type }),
|
||||
]));
|
||||
});
|
||||
});
|
||||
@@ -168,12 +168,6 @@ function _migrateIntoDefaultProject(workspace: Workspace) {
|
||||
return workspace;
|
||||
}
|
||||
|
||||
export async function ensureChildren({ _id }: Workspace) {
|
||||
await models.environment.getOrCreateForParentId(_id);
|
||||
await models.cookieJar.getOrCreateForParentId(_id);
|
||||
await models.workspaceMeta.getOrCreateByParentId(_id);
|
||||
}
|
||||
|
||||
function expectParentToBeProject(parentId?: string | null) {
|
||||
if (parentId && !isProjectId(parentId)) {
|
||||
throw new Error('Expected the parent of a Workspace to be a Project');
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import { createBuilder } from '@develohpanda/fluent-builder';
|
||||
import { afterAll, beforeEach, describe, expect, it, jest } from '@jest/globals';
|
||||
|
||||
import { globalBeforeEach } from '../../../__jest__/before-each';
|
||||
import * as models from '../../../models';
|
||||
import { snapshotStateEntrySchema } from '../../__schemas__/type-schemas';
|
||||
import MemoryDriver from '../../store/drivers/memory-driver';
|
||||
import { Snapshot } from '../../types';
|
||||
import { initializeLocalBackendProjectAndMarkForSync, pushSnapshotOnInitialize } from '../initialize-backend-project';
|
||||
import { VCS } from '../vcs';
|
||||
|
||||
const snapshotStateBuilder = createBuilder(snapshotStateEntrySchema);
|
||||
|
||||
describe('initialize-backend-project', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
|
||||
@@ -18,7 +13,6 @@ describe('initialize-backend-project', () => {
|
||||
it('should do nothing if not request collection', async () => {
|
||||
// Arrange
|
||||
const workspace = await models.workspace.create({ scope: 'design' });
|
||||
await models.workspace.ensureChildren(workspace);
|
||||
const vcs = new VCS(new MemoryDriver());
|
||||
const switchAndCreateBackendProjectIfNotExistSpy = jest.spyOn(vcs, 'switchAndCreateBackendProjectIfNotExist');
|
||||
|
||||
@@ -27,44 +21,10 @@ describe('initialize-backend-project', () => {
|
||||
|
||||
// Assert
|
||||
expect(switchAndCreateBackendProjectIfNotExistSpy).not.toHaveBeenCalled();
|
||||
const workspaceMeta = await models.workspaceMeta.getByParentId(workspace._id);
|
||||
expect(workspaceMeta?.pushSnapshotOnInitialize).toBe(false);
|
||||
// const workspaceMeta = await models.workspaceMeta.getByParentId(workspace._id);
|
||||
// expect(workspaceMeta?.pushSnapshotOnInitialize).toBe(false);
|
||||
switchAndCreateBackendProjectIfNotExistSpy.mockClear();
|
||||
});
|
||||
it('should create a local project and commit', async () => {
|
||||
const workspace = await models.workspace.create();
|
||||
await models.workspace.ensureChildren(workspace);
|
||||
|
||||
const environment = await models.environment.getByParentId(workspace._id);
|
||||
|
||||
const vcs = new VCS(new MemoryDriver());
|
||||
|
||||
await initializeLocalBackendProjectAndMarkForSync({ workspace, vcs });
|
||||
|
||||
const historyCount = await vcs.getHistoryCount();
|
||||
expect(historyCount).toBe(1);
|
||||
const firstSnapshot = (await vcs.getHistory(1))[0];
|
||||
|
||||
expect(firstSnapshot).toMatchObject<Partial<Snapshot>>({
|
||||
name: 'Initial Snapshot',
|
||||
parent: '0000000000000000000000000000000000000000',
|
||||
state: [
|
||||
snapshotStateBuilder
|
||||
.blob(expect.stringMatching(/.+/))
|
||||
.key(workspace._id)
|
||||
.name(workspace.name)
|
||||
.build(),
|
||||
snapshotStateBuilder
|
||||
.blob(expect.stringMatching(/.+/))
|
||||
.key(environment?._id || '')
|
||||
.name(environment?.name || '')
|
||||
.build(),
|
||||
],
|
||||
});
|
||||
|
||||
const workspaceMeta = await models.workspaceMeta.getByParentId(workspace._id);
|
||||
expect(workspaceMeta?.pushSnapshotOnInitialize).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('pushSnapshotOnInitialize()', () => {
|
||||
@@ -114,7 +74,7 @@ describe('initialize-backend-project', () => {
|
||||
await pushSnapshotOnInitialize({ vcs, project, workspace, workspaceMeta });
|
||||
|
||||
expect(pushSpy).not.toHaveBeenCalled();
|
||||
await expect(models.workspaceMeta.getByParentId(workspace._id)).resolves.toStrictEqual(workspaceMeta);
|
||||
// await expect(models.workspaceMeta.getByParentId(workspace._id)).resolves.toStrictEqual(workspaceMeta);
|
||||
});
|
||||
|
||||
it('should not push snapshot if not marked for push', async () => {
|
||||
|
||||
@@ -520,7 +520,11 @@ async function renderApp() {
|
||||
|
||||
const { _id: workspaceId } = workspace;
|
||||
|
||||
await models.workspace.ensureChildren(workspace);
|
||||
// Create default env, cookie jar, and meta
|
||||
await models.environment.getOrCreateForParentId(workspace._id);
|
||||
await models.cookieJar.getOrCreateForParentId(workspace._id);
|
||||
await models.workspaceMeta.getOrCreateByParentId(workspace._id);
|
||||
|
||||
const request = await models.request.create({ parentId: workspaceId });
|
||||
|
||||
const unitTestSuite = await models.unitTestSuite.create({
|
||||
|
||||
@@ -4,7 +4,7 @@ import thunk from 'redux-thunk';
|
||||
|
||||
import { globalBeforeEach } from '../../../../__jest__/before-each';
|
||||
import { reduxStateForTest } from '../../../../__jest__/redux-state-for-test';
|
||||
import { ACTIVITY_DEBUG, ACTIVITY_SPEC, ACTIVITY_UNIT_TEST } from '../../../../common/constants';
|
||||
import { ACTIVITY_DEBUG, ACTIVITY_SPEC } from '../../../../common/constants';
|
||||
import * as models from '../../../../models';
|
||||
import { SET_ACTIVE_ACTIVITY, SET_ACTIVE_PROJECT, SET_ACTIVE_WORKSPACE } from '../global';
|
||||
import { activateWorkspace } from '../workspace';
|
||||
@@ -95,25 +95,6 @@ describe('workspace', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([ACTIVITY_UNIT_TEST, ACTIVITY_SPEC, ACTIVITY_DEBUG])('should not switch activity if already in a supported design activity: %s', async activeActivity => {
|
||||
const project = await models.project.create();
|
||||
const workspace = await models.workspace.create({ scope: 'design', parentId: project._id });
|
||||
const store = mockStore(await reduxStateForTest({ activeProjectId: project._id, activeWorkspaceId: workspace._id, activeActivity }));
|
||||
|
||||
await store.dispatch(activateWorkspace({ workspace }));
|
||||
|
||||
expect(store.getActions()).toEqual([
|
||||
{
|
||||
type: SET_ACTIVE_PROJECT,
|
||||
projectId: project._id,
|
||||
},
|
||||
{
|
||||
type: SET_ACTIVE_WORKSPACE,
|
||||
workspaceId: workspace._id,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([ACTIVITY_DEBUG])('should not switch activity if already in a supported collection activity: %s', async activeActivity => {
|
||||
const project = await models.project.create();
|
||||
const workspace = await models.workspace.create({ scope: 'design', parentId: project._id });
|
||||
@@ -155,30 +136,5 @@ describe('workspace', () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should switch to the cached activity', async () => {
|
||||
const project = await models.project.create();
|
||||
const workspace = await models.workspace.create({ scope: 'design', parentId: project._id });
|
||||
await models.workspace.ensureChildren(workspace);
|
||||
await models.workspaceMeta.updateByParentId(workspace._id, { activeActivity: ACTIVITY_UNIT_TEST });
|
||||
const store = mockStore(await reduxStateForTest({ activeProjectId: project._id, activeWorkspaceId: workspace._id }));
|
||||
|
||||
await store.dispatch(activateWorkspace({ workspace }));
|
||||
|
||||
expect(store.getActions()).toEqual([
|
||||
{
|
||||
type: SET_ACTIVE_PROJECT,
|
||||
projectId: project._id,
|
||||
},
|
||||
{
|
||||
type: SET_ACTIVE_WORKSPACE,
|
||||
workspaceId: workspace._id,
|
||||
},
|
||||
{
|
||||
type: SET_ACTIVE_ACTIVITY,
|
||||
activity: ACTIVITY_UNIT_TEST,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -98,7 +98,10 @@ export const createNewWorkspaceAction: ActionFunction = async ({
|
||||
scope,
|
||||
parentId: projectId,
|
||||
});
|
||||
await models.workspace.ensureChildren(workspace);
|
||||
|
||||
// Create default env, cookie jar, and meta
|
||||
await models.environment.getOrCreateForParentId(workspace._id);
|
||||
await models.cookieJar.getOrCreateForParentId(workspace._id);
|
||||
await models.workspaceMeta.getOrCreateByParentId(workspace._id);
|
||||
|
||||
await database.flushChanges(flushId);
|
||||
@@ -185,7 +188,10 @@ export const duplicateWorkspaceAction: ActionFunction = async ({ request, params
|
||||
parentId: projectId,
|
||||
});
|
||||
|
||||
await models.workspace.ensureChildren(newWorkspace);
|
||||
// Create default env, cookie jar, and meta
|
||||
await models.environment.getOrCreateForParentId(newWorkspace._id);
|
||||
await models.cookieJar.getOrCreateForParentId(newWorkspace._id);
|
||||
await models.workspaceMeta.getOrCreateByParentId(newWorkspace._id);
|
||||
|
||||
try {
|
||||
// Mark for sync if logged in and in the expected project
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import { LoaderFunction, Outlet, useLoaderData } from 'react-router-dom';
|
||||
|
||||
import { database } from '../../common/database';
|
||||
import * as models from '../../models';
|
||||
import { GitRepository } from '../../models/git-repository';
|
||||
import { Project } from '../../models/project';
|
||||
@@ -27,22 +26,15 @@ export const workspaceLoader: LoaderFunction = async ({
|
||||
|
||||
invariant(workspace, 'Workspace not found');
|
||||
|
||||
const workspaceEnvironments = await models.environment.findByParentId(workspaceId);
|
||||
// I don't know what to say man, this is just how it is
|
||||
await models.environment.getOrCreateForParentId(workspaceId);
|
||||
await models.cookieJar.getOrCreateForParentId(workspaceId);
|
||||
await models.workspaceMeta.getOrCreateByParentId(workspaceId);
|
||||
const workspaceMeta = await models.workspaceMeta.getOrCreateByParentId(workspaceId);
|
||||
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspaceId);
|
||||
const apiSpec = await models.apiSpec.getByParentId(workspaceId);
|
||||
const activeProject = await models.project.getById(projectId);
|
||||
invariant(activeProject, 'Project not found');
|
||||
|
||||
const gitRepository = await models.gitRepository.getById(workspaceMeta.gitRepositoryId || '');
|
||||
|
||||
const workspaceHasChildren = workspaceEnvironments.length && cookieJar && apiSpec && workspaceMeta;
|
||||
if (!workspaceHasChildren) {
|
||||
const flushId = await database.bufferChanges();
|
||||
await models.workspace.ensureChildren(workspace);
|
||||
await database.flushChanges(flushId);
|
||||
}
|
||||
|
||||
return {
|
||||
activeWorkspace: workspace,
|
||||
activeProject,
|
||||
|
||||
Reference in new issue
Block a user