@malloy-publisher/server 0.0.195 → 0.0.196
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/api-doc.yaml +213 -214
- package/dist/app/assets/EnvironmentPage-1j6QDWAy.js +1 -0
- package/dist/app/assets/HomePage-DMop21VG.js +1 -0
- package/dist/app/assets/MainPage-BbE8ETz1.js +2 -0
- package/dist/app/assets/ModelPage-D2jvfe3t.js +1 -0
- package/dist/app/assets/PackagePage-BbnhGoD3.js +1 -0
- package/dist/app/assets/{RouteError-DefbDO7F.js → RouteError-D3LGEZ3i.js} +1 -1
- package/dist/app/assets/WorkbookPage-DttVIj4u.js +1 -0
- package/dist/app/assets/{core-BrfQApxh.es-DnvCX4oH.js → core-w79IMXAG.es-Bd0UlzOL.js} +1 -1
- package/dist/app/assets/{index-Bu0ub036.js → index-5K9YjIxF.js} +117 -117
- package/dist/app/assets/{index-CkzK3JIl.js → index-C513UodQ.js} +1 -1
- package/dist/app/assets/{index-CoA6HIGS.js → index-DIgzgp69.js} +1 -1
- package/dist/app/assets/{index.umd-B6Ms2PpL.js → index.umd-BMeMPq_9.js} +1 -1
- package/dist/app/index.html +1 -1
- package/dist/server.mjs +1976 -1322
- package/package.json +2 -2
- package/publisher.config.json +2 -2
- package/src/config.spec.ts +181 -66
- package/src/config.ts +68 -47
- package/src/controller/compile.controller.ts +10 -7
- package/src/controller/connection.controller.ts +79 -58
- package/src/controller/database.controller.ts +10 -7
- package/src/controller/manifest.controller.ts +23 -14
- package/src/controller/materialization.controller.ts +14 -14
- package/src/controller/model.controller.ts +35 -20
- package/src/controller/package.controller.ts +83 -49
- package/src/controller/query.controller.ts +11 -8
- package/src/controller/watch-mode.controller.ts +35 -29
- package/src/errors.ts +2 -2
- package/src/mcp/error_messages.ts +2 -2
- package/src/mcp/handler_utils.ts +23 -20
- package/src/mcp/mcp_constants.ts +1 -1
- package/src/mcp/prompts/handlers.ts +3 -3
- package/src/mcp/prompts/prompt_service.ts +5 -5
- package/src/mcp/prompts/utils.ts +12 -12
- package/src/mcp/resource_metadata.ts +3 -3
- package/src/mcp/resources/environment_resource.ts +187 -0
- package/src/mcp/resources/model_resource.ts +19 -17
- package/src/mcp/resources/notebook_resource.ts +13 -13
- package/src/mcp/resources/package_resource.ts +30 -27
- package/src/mcp/resources/query_resource.ts +15 -10
- package/src/mcp/resources/source_resource.ts +10 -10
- package/src/mcp/resources/view_resource.ts +11 -11
- package/src/mcp/server.ts +16 -14
- package/src/mcp/tools/discovery_tools.ts +67 -49
- package/src/mcp/tools/execute_query_tool.ts +14 -14
- package/src/server-old.ts +1119 -0
- package/src/server.ts +191 -159
- package/src/service/connection.spec.ts +158 -133
- package/src/service/connection.ts +42 -39
- package/src/service/connection_config.spec.ts +13 -11
- package/src/service/connection_config.ts +28 -19
- package/src/service/connection_service.spec.ts +63 -43
- package/src/service/connection_service.ts +106 -89
- package/src/service/{project.ts → environment.ts} +92 -77
- package/src/service/{project_compile.spec.ts → environment_compile.spec.ts} +1 -1
- package/src/service/{project_store.spec.ts → environment_store.spec.ts} +99 -83
- package/src/service/{project_store.ts → environment_store.ts} +373 -327
- package/src/service/manifest_service.spec.ts +15 -15
- package/src/service/manifest_service.ts +26 -21
- package/src/service/materialization_service.spec.ts +93 -59
- package/src/service/materialization_service.ts +71 -62
- package/src/service/materialized_table_gc.spec.ts +15 -15
- package/src/service/materialized_table_gc.ts +3 -3
- package/src/service/model.ts +4 -4
- package/src/service/package.spec.ts +2 -2
- package/src/service/package.ts +23 -21
- package/src/service/resolve_environment.ts +15 -0
- package/src/storage/DatabaseInterface.ts +34 -25
- package/src/storage/StorageManager.mock.ts +3 -3
- package/src/storage/StorageManager.ts +64 -28
- package/src/storage/duckdb/ConnectionRepository.ts +13 -11
- package/src/storage/duckdb/DuckDBConnection.ts +1 -1
- package/src/storage/duckdb/DuckDBManifestStore.ts +6 -6
- package/src/storage/duckdb/DuckDBRepository.ts +47 -47
- package/src/storage/duckdb/{ProjectRepository.ts → EnvironmentRepository.ts} +35 -35
- package/src/storage/duckdb/ManifestRepository.ts +21 -20
- package/src/storage/duckdb/MaterializationRepository.ts +31 -28
- package/src/storage/duckdb/PackageRepository.ts +11 -11
- package/src/storage/duckdb/manifest_store.spec.ts +2 -2
- package/src/storage/duckdb/schema.ts +61 -20
- package/src/storage/ducklake/DuckLakeManifestStore.ts +20 -11
- package/tests/fixtures/publisher.config.json +1 -1
- package/tests/harness/e2e.ts +1 -1
- package/tests/harness/mcp_test_setup.ts +12 -24
- package/tests/harness/mocks.ts +10 -8
- package/tests/harness/rest_e2e.ts +2 -2
- package/tests/integration/legacy_routes/legacy_routes.integration.spec.ts +259 -0
- package/tests/integration/materialization/materialization_lifecycle.integration.spec.ts +4 -4
- package/tests/integration/mcp/mcp_execute_query_tool.integration.spec.ts +28 -49
- package/tests/integration/mcp/mcp_resource.integration.spec.ts +39 -47
- package/tests/integration/mcp/mcp_transport.integration.spec.ts +1 -1
- package/tests/unit/duckdb/attached_databases.test.ts +51 -33
- package/tests/unit/duckdb/legacy_schema_migration.test.ts +194 -0
- package/tests/unit/ducklake/ducklake.test.ts +24 -22
- package/tests/unit/mcp/prompt_happy.test.ts +8 -8
- package/dist/app/assets/HomePage-DbZS0N7G.js +0 -1
- package/dist/app/assets/MainPage-CBuWkbmr.js +0 -2
- package/dist/app/assets/ModelPage-Bt37smot.js +0 -1
- package/dist/app/assets/PackagePage-DLZe50WG.js +0 -1
- package/dist/app/assets/ProjectPage-FQTEPXP4.js +0 -1
- package/dist/app/assets/WorkbookPage-CkAo16ar.js +0 -1
- package/src/mcp/resources/project_resource.ts +0 -184
- package/src/service/resolve_project.ts +0 -13
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
ResourceRepository,
|
|
8
8
|
} from "../storage/DatabaseInterface";
|
|
9
9
|
import { ManifestService } from "./manifest_service";
|
|
10
|
-
import {
|
|
10
|
+
import { EnvironmentStore } from "./environment_store";
|
|
11
11
|
|
|
12
12
|
function makeEntry(overrides: Partial<ManifestEntry> = {}): ManifestEntry {
|
|
13
13
|
return {
|
|
14
14
|
id: "entry-1",
|
|
15
|
-
|
|
15
|
+
environmentId: "proj-1",
|
|
16
16
|
packageName: "pkg",
|
|
17
17
|
buildId: "build-abc",
|
|
18
18
|
tableName: "my_table",
|
|
@@ -44,26 +44,26 @@ function createMocks() {
|
|
|
44
44
|
reloadAllModels,
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
const
|
|
47
|
+
const environment = {
|
|
48
48
|
getPackage: sandbox.stub().resolves(pkg),
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
const
|
|
51
|
+
const environmentStore = {
|
|
52
52
|
storageManager: {
|
|
53
|
-
getManifestStore: (
|
|
53
|
+
getManifestStore: (_environmentId?: string) => manifestStore,
|
|
54
54
|
getRepository: () => repository,
|
|
55
55
|
},
|
|
56
|
-
|
|
57
|
-
} as unknown as
|
|
56
|
+
getEnvironment: sandbox.stub().resolves(environment),
|
|
57
|
+
} as unknown as EnvironmentStore;
|
|
58
58
|
|
|
59
|
-
const service = new ManifestService(
|
|
59
|
+
const service = new ManifestService(environmentStore);
|
|
60
60
|
|
|
61
61
|
return {
|
|
62
62
|
sandbox,
|
|
63
63
|
manifestStore,
|
|
64
64
|
repository,
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
environmentStore,
|
|
66
|
+
environment,
|
|
67
67
|
pkg,
|
|
68
68
|
reloadAllModels,
|
|
69
69
|
service,
|
|
@@ -142,17 +142,17 @@ describe("ManifestService", () => {
|
|
|
142
142
|
const result = await ctx.service.reloadManifest(
|
|
143
143
|
"proj-1",
|
|
144
144
|
"pkg",
|
|
145
|
-
"my-
|
|
145
|
+
"my-environment",
|
|
146
146
|
);
|
|
147
147
|
|
|
148
148
|
expect(result).toEqual(manifest);
|
|
149
149
|
expect(
|
|
150
|
-
(ctx.
|
|
151
|
-
"my-
|
|
150
|
+
(ctx.environmentStore.getEnvironment as sinon.SinonStub).calledWith(
|
|
151
|
+
"my-environment",
|
|
152
152
|
false,
|
|
153
153
|
),
|
|
154
154
|
).toBe(true);
|
|
155
|
-
expect(ctx.
|
|
155
|
+
expect(ctx.environment.getPackage.calledWith("pkg", false)).toBe(true);
|
|
156
156
|
expect(ctx.reloadAllModels.calledWith(manifest.entries)).toBe(true);
|
|
157
157
|
});
|
|
158
158
|
|
|
@@ -166,7 +166,7 @@ describe("ManifestService", () => {
|
|
|
166
166
|
const result = await ctx.service.reloadManifest(
|
|
167
167
|
"proj-1",
|
|
168
168
|
"pkg",
|
|
169
|
-
"my-
|
|
169
|
+
"my-environment",
|
|
170
170
|
);
|
|
171
171
|
|
|
172
172
|
expect(result.entries).toEqual({});
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
ManifestEntry,
|
|
5
5
|
ManifestStore,
|
|
6
6
|
} from "../storage/DatabaseInterface";
|
|
7
|
-
import {
|
|
7
|
+
import { EnvironmentStore } from "./environment_store";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Manages build manifests that map source names to materialized table names.
|
|
@@ -23,32 +23,34 @@ import { ProjectStore } from "./project_store";
|
|
|
23
23
|
* is either the local DuckDB store (standalone) or DuckLake (orchestrated).
|
|
24
24
|
*/
|
|
25
25
|
export class ManifestService {
|
|
26
|
-
constructor(private
|
|
26
|
+
constructor(private environmentStore: EnvironmentStore) {}
|
|
27
27
|
|
|
28
|
-
private manifestStoreFor(
|
|
29
|
-
return this.
|
|
28
|
+
private manifestStoreFor(environmentId: string): ManifestStore {
|
|
29
|
+
return this.environmentStore.storageManager.getManifestStore(
|
|
30
|
+
environmentId,
|
|
31
|
+
);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
async getManifest(
|
|
33
|
-
|
|
35
|
+
environmentId: string,
|
|
34
36
|
packageName: string,
|
|
35
37
|
): Promise<BuildManifest> {
|
|
36
|
-
return this.manifestStoreFor(
|
|
37
|
-
|
|
38
|
+
return this.manifestStoreFor(environmentId).getManifest(
|
|
39
|
+
environmentId,
|
|
38
40
|
packageName,
|
|
39
41
|
);
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
async writeEntry(
|
|
43
|
-
|
|
45
|
+
environmentId: string,
|
|
44
46
|
packageName: string,
|
|
45
47
|
buildId: string,
|
|
46
48
|
tableName: string,
|
|
47
49
|
sourceName: string,
|
|
48
50
|
connectionName: string,
|
|
49
51
|
): Promise<void> {
|
|
50
|
-
await this.manifestStoreFor(
|
|
51
|
-
|
|
52
|
+
await this.manifestStoreFor(environmentId).writeEntry(
|
|
53
|
+
environmentId,
|
|
52
54
|
packageName,
|
|
53
55
|
buildId,
|
|
54
56
|
tableName,
|
|
@@ -57,8 +59,8 @@ export class ManifestService {
|
|
|
57
59
|
);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
async deleteEntry(
|
|
61
|
-
await this.manifestStoreFor(
|
|
62
|
+
async deleteEntry(environmentId: string, entryId: string): Promise<void> {
|
|
63
|
+
await this.manifestStoreFor(environmentId).deleteEntry(entryId);
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
/**
|
|
@@ -70,18 +72,21 @@ export class ManifestService {
|
|
|
70
72
|
* storage — the worker pulls the manifest down and recompiles.
|
|
71
73
|
*/
|
|
72
74
|
async reloadManifest(
|
|
73
|
-
|
|
75
|
+
environmentId: string,
|
|
74
76
|
packageName: string,
|
|
75
|
-
|
|
77
|
+
environmentName: string,
|
|
76
78
|
): Promise<BuildManifest> {
|
|
77
|
-
const manifest = await this.getManifest(
|
|
79
|
+
const manifest = await this.getManifest(environmentId, packageName);
|
|
78
80
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
+
const environment = await this.environmentStore.getEnvironment(
|
|
82
|
+
environmentName,
|
|
83
|
+
false,
|
|
84
|
+
);
|
|
85
|
+
const pkg = await environment.getPackage(packageName, false);
|
|
81
86
|
await pkg.reloadAllModels(manifest.entries);
|
|
82
87
|
|
|
83
88
|
logger.info("Reloaded manifest and recompiled models", {
|
|
84
|
-
|
|
89
|
+
environmentId,
|
|
85
90
|
packageName,
|
|
86
91
|
entryCount: Object.keys(manifest.entries).length,
|
|
87
92
|
});
|
|
@@ -95,11 +100,11 @@ export class ManifestService {
|
|
|
95
100
|
* catalog instead of the local DuckDB table.
|
|
96
101
|
*/
|
|
97
102
|
async listEntries(
|
|
98
|
-
|
|
103
|
+
environmentId: string,
|
|
99
104
|
packageName: string,
|
|
100
105
|
): Promise<ManifestEntry[]> {
|
|
101
|
-
return this.manifestStoreFor(
|
|
102
|
-
|
|
106
|
+
return this.manifestStoreFor(environmentId).listEntries(
|
|
107
|
+
environmentId,
|
|
103
108
|
packageName,
|
|
104
109
|
);
|
|
105
110
|
}
|
|
@@ -2,32 +2,32 @@ import type { Connection } from "@malloydata/malloy";
|
|
|
2
2
|
import { beforeEach, describe, expect, it } from "bun:test";
|
|
3
3
|
import * as sinon from "sinon";
|
|
4
4
|
import {
|
|
5
|
+
EnvironmentNotFoundError,
|
|
5
6
|
InvalidStateTransitionError,
|
|
6
7
|
MaterializationConflictError,
|
|
7
8
|
MaterializationNotFoundError,
|
|
8
|
-
ProjectNotFoundError,
|
|
9
9
|
} from "../errors";
|
|
10
|
-
import { DuplicateActiveMaterializationError } from "../storage/duckdb/MaterializationRepository";
|
|
11
10
|
import {
|
|
12
11
|
ManifestEntry,
|
|
13
12
|
Materialization,
|
|
14
13
|
MaterializationStatus,
|
|
15
14
|
ResourceRepository,
|
|
16
15
|
} from "../storage/DatabaseInterface";
|
|
16
|
+
import { DuplicateActiveMaterializationError } from "../storage/duckdb/MaterializationRepository";
|
|
17
|
+
import { EnvironmentStore } from "./environment_store";
|
|
17
18
|
import { ManifestService } from "./manifest_service";
|
|
18
19
|
import {
|
|
19
20
|
manifestTableKey,
|
|
20
21
|
MaterializationService,
|
|
21
22
|
tablePhysicallyExists,
|
|
22
23
|
} from "./materialization_service";
|
|
23
|
-
import { ProjectStore } from "./project_store";
|
|
24
24
|
|
|
25
25
|
function makeExecution(
|
|
26
26
|
overrides: Partial<Materialization> = {},
|
|
27
27
|
): Materialization {
|
|
28
28
|
return {
|
|
29
29
|
id: "exec-1",
|
|
30
|
-
|
|
30
|
+
environmentId: "proj-1",
|
|
31
31
|
packageName: "pkg",
|
|
32
32
|
status: "PENDING",
|
|
33
33
|
startedAt: null,
|
|
@@ -46,12 +46,12 @@ function createMocks() {
|
|
|
46
46
|
const sandbox = sinon.createSandbox();
|
|
47
47
|
|
|
48
48
|
const repository: MockRepo = {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
listEnvironments: sandbox.stub(),
|
|
50
|
+
getEnvironmentById: sandbox.stub(),
|
|
51
|
+
getEnvironmentByName: sandbox.stub(),
|
|
52
|
+
createEnvironment: sandbox.stub(),
|
|
53
|
+
updateEnvironment: sandbox.stub(),
|
|
54
|
+
deleteEnvironment: sandbox.stub(),
|
|
55
55
|
listPackages: sandbox.stub(),
|
|
56
56
|
getPackageById: sandbox.stub(),
|
|
57
57
|
getPackageByName: sandbox.stub(),
|
|
@@ -80,10 +80,10 @@ function createMocks() {
|
|
|
80
80
|
getManifestStore: sandbox.stub(),
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
const
|
|
83
|
+
const environmentStore = {
|
|
84
84
|
storageManager,
|
|
85
|
-
|
|
86
|
-
} as unknown as
|
|
85
|
+
getEnvironment: sandbox.stub(),
|
|
86
|
+
} as unknown as EnvironmentStore;
|
|
87
87
|
|
|
88
88
|
const manifestService = {
|
|
89
89
|
getManifest: sandbox.stub().resolves({ entries: {}, strict: false }),
|
|
@@ -94,20 +94,20 @@ function createMocks() {
|
|
|
94
94
|
} as unknown as sinon.SinonStubbedInstance<ManifestService>;
|
|
95
95
|
|
|
96
96
|
const service = new MaterializationService(
|
|
97
|
-
|
|
97
|
+
environmentStore,
|
|
98
98
|
manifestService as unknown as ManifestService,
|
|
99
99
|
);
|
|
100
100
|
|
|
101
|
-
// Default:
|
|
102
|
-
repository.
|
|
101
|
+
// Default: resolveEnvironmentId succeeds
|
|
102
|
+
repository.getEnvironmentByName.resolves({
|
|
103
103
|
id: "proj-1",
|
|
104
|
-
name: "my-
|
|
104
|
+
name: "my-environment",
|
|
105
105
|
path: "/test",
|
|
106
106
|
createdAt: new Date(),
|
|
107
107
|
updatedAt: new Date(),
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
-
return { sandbox, repository,
|
|
110
|
+
return { sandbox, repository, environmentStore, manifestService, service };
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
describe("MaterializationService", () => {
|
|
@@ -117,15 +117,15 @@ describe("MaterializationService", () => {
|
|
|
117
117
|
ctx = createMocks();
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
// ====================
|
|
120
|
+
// ==================== resolveEnvironmentId ====================
|
|
121
121
|
|
|
122
|
-
describe("
|
|
123
|
-
it("should throw
|
|
124
|
-
ctx.repository.
|
|
122
|
+
describe("resolveEnvironmentId (via listMaterializations)", () => {
|
|
123
|
+
it("should throw EnvironmentNotFoundError when environment is not in DB", async () => {
|
|
124
|
+
ctx.repository.getEnvironmentByName.resolves(null);
|
|
125
125
|
|
|
126
126
|
await expect(
|
|
127
127
|
ctx.service.listMaterializations("unknown", "pkg"),
|
|
128
|
-
).rejects.toThrow(
|
|
128
|
+
).rejects.toThrow(EnvironmentNotFoundError);
|
|
129
129
|
});
|
|
130
130
|
});
|
|
131
131
|
|
|
@@ -137,7 +137,7 @@ describe("MaterializationService", () => {
|
|
|
137
137
|
ctx.repository.listMaterializations.resolves(builds);
|
|
138
138
|
|
|
139
139
|
const result = await ctx.service.listMaterializations(
|
|
140
|
-
"my-
|
|
140
|
+
"my-environment",
|
|
141
141
|
"pkg",
|
|
142
142
|
);
|
|
143
143
|
|
|
@@ -151,7 +151,7 @@ describe("MaterializationService", () => {
|
|
|
151
151
|
ctx.repository.getMaterializationById.resolves(exec);
|
|
152
152
|
|
|
153
153
|
const result = await ctx.service.getMaterialization(
|
|
154
|
-
"my-
|
|
154
|
+
"my-environment",
|
|
155
155
|
"pkg",
|
|
156
156
|
"exec-1",
|
|
157
157
|
);
|
|
@@ -163,7 +163,7 @@ describe("MaterializationService", () => {
|
|
|
163
163
|
ctx.repository.getMaterializationById.resolves(null);
|
|
164
164
|
|
|
165
165
|
await expect(
|
|
166
|
-
ctx.service.getMaterialization("my-
|
|
166
|
+
ctx.service.getMaterialization("my-environment", "pkg", "missing"),
|
|
167
167
|
).rejects.toThrow(MaterializationNotFoundError);
|
|
168
168
|
});
|
|
169
169
|
|
|
@@ -173,7 +173,7 @@ describe("MaterializationService", () => {
|
|
|
173
173
|
);
|
|
174
174
|
|
|
175
175
|
await expect(
|
|
176
|
-
ctx.service.getMaterialization("my-
|
|
176
|
+
ctx.service.getMaterialization("my-environment", "pkg", "exec-1"),
|
|
177
177
|
).rejects.toThrow(MaterializationNotFoundError);
|
|
178
178
|
});
|
|
179
179
|
});
|
|
@@ -216,7 +216,7 @@ describe("MaterializationService", () => {
|
|
|
216
216
|
// Trigger via stopMaterialization for RUNNING->CANCELLED (orphaned path)
|
|
217
217
|
if (from === "RUNNING" && to === "CANCELLED") {
|
|
218
218
|
const result = await ctx.service.stopMaterialization(
|
|
219
|
-
"my-
|
|
219
|
+
"my-environment",
|
|
220
220
|
"pkg",
|
|
221
221
|
exec.id,
|
|
222
222
|
);
|
|
@@ -242,7 +242,7 @@ describe("MaterializationService", () => {
|
|
|
242
242
|
|
|
243
243
|
describe("createMaterialization", () => {
|
|
244
244
|
it("should create a PENDING build", async () => {
|
|
245
|
-
(ctx.
|
|
245
|
+
(ctx.environmentStore.getEnvironment as sinon.SinonStub).resolves({
|
|
246
246
|
getPackage: sinon.stub().resolves({}),
|
|
247
247
|
});
|
|
248
248
|
ctx.repository.getActiveMaterialization.resolves(null);
|
|
@@ -253,7 +253,7 @@ describe("MaterializationService", () => {
|
|
|
253
253
|
ctx.repository.createMaterialization.resolves(pending);
|
|
254
254
|
|
|
255
255
|
const result = await ctx.service.createMaterialization(
|
|
256
|
-
"my-
|
|
256
|
+
"my-environment",
|
|
257
257
|
"pkg",
|
|
258
258
|
{
|
|
259
259
|
autoLoadManifest: true,
|
|
@@ -276,7 +276,7 @@ describe("MaterializationService", () => {
|
|
|
276
276
|
});
|
|
277
277
|
|
|
278
278
|
it("should reject creation when an active materialization exists", async () => {
|
|
279
|
-
(ctx.
|
|
279
|
+
(ctx.environmentStore.getEnvironment as sinon.SinonStub).resolves({
|
|
280
280
|
getPackage: sinon.stub().resolves({}),
|
|
281
281
|
});
|
|
282
282
|
ctx.repository.getActiveMaterialization.resolves(
|
|
@@ -284,12 +284,12 @@ describe("MaterializationService", () => {
|
|
|
284
284
|
);
|
|
285
285
|
|
|
286
286
|
await expect(
|
|
287
|
-
ctx.service.createMaterialization("my-
|
|
287
|
+
ctx.service.createMaterialization("my-environment", "pkg"),
|
|
288
288
|
).rejects.toThrow(MaterializationConflictError);
|
|
289
289
|
});
|
|
290
290
|
|
|
291
291
|
it("should translate DuplicateActiveMaterializationError from a lost race", async () => {
|
|
292
|
-
(ctx.
|
|
292
|
+
(ctx.environmentStore.getEnvironment as sinon.SinonStub).resolves({
|
|
293
293
|
getPackage: sinon.stub().resolves({}),
|
|
294
294
|
});
|
|
295
295
|
// The pre-check finds nothing (race is still possible), but the
|
|
@@ -305,7 +305,7 @@ describe("MaterializationService", () => {
|
|
|
305
305
|
);
|
|
306
306
|
|
|
307
307
|
await expect(
|
|
308
|
-
ctx.service.createMaterialization("my-
|
|
308
|
+
ctx.service.createMaterialization("my-environment", "pkg"),
|
|
309
309
|
).rejects.toThrow(/winner/);
|
|
310
310
|
});
|
|
311
311
|
});
|
|
@@ -322,7 +322,7 @@ describe("MaterializationService", () => {
|
|
|
322
322
|
ctx.repository.updateMaterialization.resolves(running);
|
|
323
323
|
|
|
324
324
|
const result = await ctx.service.startMaterialization(
|
|
325
|
-
"my-
|
|
325
|
+
"my-environment",
|
|
326
326
|
"pkg",
|
|
327
327
|
"exec-1",
|
|
328
328
|
);
|
|
@@ -335,7 +335,7 @@ describe("MaterializationService", () => {
|
|
|
335
335
|
ctx.repository.getMaterializationById.resolves(running);
|
|
336
336
|
|
|
337
337
|
await expect(
|
|
338
|
-
ctx.service.startMaterialization("my-
|
|
338
|
+
ctx.service.startMaterialization("my-environment", "pkg", "exec-1"),
|
|
339
339
|
).rejects.toThrow(InvalidStateTransitionError);
|
|
340
340
|
});
|
|
341
341
|
|
|
@@ -350,7 +350,7 @@ describe("MaterializationService", () => {
|
|
|
350
350
|
);
|
|
351
351
|
|
|
352
352
|
await expect(
|
|
353
|
-
ctx.service.startMaterialization("my-
|
|
353
|
+
ctx.service.startMaterialization("my-environment", "pkg", "exec-1"),
|
|
354
354
|
).rejects.toThrow(MaterializationConflictError);
|
|
355
355
|
});
|
|
356
356
|
});
|
|
@@ -364,7 +364,7 @@ describe("MaterializationService", () => {
|
|
|
364
364
|
);
|
|
365
365
|
|
|
366
366
|
const result = await ctx.service.stopMaterialization(
|
|
367
|
-
"my-
|
|
367
|
+
"my-environment",
|
|
368
368
|
"pkg",
|
|
369
369
|
"exec-1",
|
|
370
370
|
);
|
|
@@ -380,7 +380,7 @@ describe("MaterializationService", () => {
|
|
|
380
380
|
);
|
|
381
381
|
|
|
382
382
|
const result = await ctx.service.stopMaterialization(
|
|
383
|
-
"my-
|
|
383
|
+
"my-environment",
|
|
384
384
|
"pkg",
|
|
385
385
|
"orphan",
|
|
386
386
|
);
|
|
@@ -393,7 +393,7 @@ describe("MaterializationService", () => {
|
|
|
393
393
|
ctx.repository.getMaterializationById.resolves(succeeded);
|
|
394
394
|
|
|
395
395
|
await expect(
|
|
396
|
-
ctx.service.stopMaterialization("my-
|
|
396
|
+
ctx.service.stopMaterialization("my-environment", "pkg", "exec-1"),
|
|
397
397
|
).rejects.toThrow(InvalidStateTransitionError);
|
|
398
398
|
});
|
|
399
399
|
});
|
|
@@ -406,7 +406,11 @@ describe("MaterializationService", () => {
|
|
|
406
406
|
ctx.repository.getMaterializationById.resolves(succeeded);
|
|
407
407
|
ctx.repository.deleteMaterialization.resolves();
|
|
408
408
|
|
|
409
|
-
await ctx.service.deleteMaterialization(
|
|
409
|
+
await ctx.service.deleteMaterialization(
|
|
410
|
+
"my-environment",
|
|
411
|
+
"pkg",
|
|
412
|
+
"exec-1",
|
|
413
|
+
);
|
|
410
414
|
|
|
411
415
|
expect(ctx.repository.deleteMaterialization.calledOnce).toBe(true);
|
|
412
416
|
expect(ctx.repository.deleteMaterialization.firstCall.args[0]).toBe(
|
|
@@ -419,7 +423,11 @@ describe("MaterializationService", () => {
|
|
|
419
423
|
ctx.repository.getMaterializationById.resolves(failed);
|
|
420
424
|
ctx.repository.deleteMaterialization.resolves();
|
|
421
425
|
|
|
422
|
-
await ctx.service.deleteMaterialization(
|
|
426
|
+
await ctx.service.deleteMaterialization(
|
|
427
|
+
"my-environment",
|
|
428
|
+
"pkg",
|
|
429
|
+
"exec-1",
|
|
430
|
+
);
|
|
423
431
|
|
|
424
432
|
expect(ctx.repository.deleteMaterialization.calledOnce).toBe(true);
|
|
425
433
|
});
|
|
@@ -429,7 +437,11 @@ describe("MaterializationService", () => {
|
|
|
429
437
|
ctx.repository.getMaterializationById.resolves(cancelled);
|
|
430
438
|
ctx.repository.deleteMaterialization.resolves();
|
|
431
439
|
|
|
432
|
-
await ctx.service.deleteMaterialization(
|
|
440
|
+
await ctx.service.deleteMaterialization(
|
|
441
|
+
"my-environment",
|
|
442
|
+
"pkg",
|
|
443
|
+
"exec-1",
|
|
444
|
+
);
|
|
433
445
|
|
|
434
446
|
expect(ctx.repository.deleteMaterialization.calledOnce).toBe(true);
|
|
435
447
|
});
|
|
@@ -439,7 +451,11 @@ describe("MaterializationService", () => {
|
|
|
439
451
|
ctx.repository.getMaterializationById.resolves(pending);
|
|
440
452
|
|
|
441
453
|
await expect(
|
|
442
|
-
ctx.service.deleteMaterialization(
|
|
454
|
+
ctx.service.deleteMaterialization(
|
|
455
|
+
"my-environment",
|
|
456
|
+
"pkg",
|
|
457
|
+
"exec-1",
|
|
458
|
+
),
|
|
443
459
|
).rejects.toThrow(InvalidStateTransitionError);
|
|
444
460
|
});
|
|
445
461
|
|
|
@@ -448,7 +464,11 @@ describe("MaterializationService", () => {
|
|
|
448
464
|
ctx.repository.getMaterializationById.resolves(running);
|
|
449
465
|
|
|
450
466
|
await expect(
|
|
451
|
-
ctx.service.deleteMaterialization(
|
|
467
|
+
ctx.service.deleteMaterialization(
|
|
468
|
+
"my-environment",
|
|
469
|
+
"pkg",
|
|
470
|
+
"exec-1",
|
|
471
|
+
),
|
|
452
472
|
).rejects.toThrow(InvalidStateTransitionError);
|
|
453
473
|
});
|
|
454
474
|
|
|
@@ -456,7 +476,11 @@ describe("MaterializationService", () => {
|
|
|
456
476
|
ctx.repository.getMaterializationById.resolves(null);
|
|
457
477
|
|
|
458
478
|
await expect(
|
|
459
|
-
ctx.service.deleteMaterialization(
|
|
479
|
+
ctx.service.deleteMaterialization(
|
|
480
|
+
"my-environment",
|
|
481
|
+
"pkg",
|
|
482
|
+
"missing",
|
|
483
|
+
),
|
|
460
484
|
).rejects.toThrow(MaterializationNotFoundError);
|
|
461
485
|
});
|
|
462
486
|
});
|
|
@@ -470,7 +494,7 @@ describe("MaterializationService", () => {
|
|
|
470
494
|
);
|
|
471
495
|
|
|
472
496
|
await expect(
|
|
473
|
-
ctx.service.teardownPackage("my-
|
|
497
|
+
ctx.service.teardownPackage("my-environment", "pkg"),
|
|
474
498
|
).rejects.toThrow(MaterializationConflictError);
|
|
475
499
|
});
|
|
476
500
|
|
|
@@ -486,14 +510,14 @@ describe("MaterializationService", () => {
|
|
|
486
510
|
throw new Error(`unknown connection: ${name}`);
|
|
487
511
|
},
|
|
488
512
|
};
|
|
489
|
-
(ctx.
|
|
513
|
+
(ctx.environmentStore.getEnvironment as sinon.SinonStub).resolves({
|
|
490
514
|
getPackage: sinon.stub().resolves(pkg),
|
|
491
515
|
});
|
|
492
516
|
ctx.repository.getActiveMaterialization.resolves(null);
|
|
493
517
|
const entries: ManifestEntry[] = [
|
|
494
518
|
{
|
|
495
519
|
id: "entry-1",
|
|
496
|
-
|
|
520
|
+
environmentId: "proj-1",
|
|
497
521
|
packageName: "pkg",
|
|
498
522
|
buildId: "abcdef1234567890abcdef1234567890",
|
|
499
523
|
tableName: "table_a",
|
|
@@ -504,7 +528,7 @@ describe("MaterializationService", () => {
|
|
|
504
528
|
},
|
|
505
529
|
{
|
|
506
530
|
id: "entry-2",
|
|
507
|
-
|
|
531
|
+
environmentId: "proj-1",
|
|
508
532
|
packageName: "pkg",
|
|
509
533
|
buildId: "1234567890abcdef1234567890abcdef",
|
|
510
534
|
tableName: "table_b",
|
|
@@ -516,7 +540,10 @@ describe("MaterializationService", () => {
|
|
|
516
540
|
];
|
|
517
541
|
(ctx.manifestService.listEntries as sinon.SinonStub).resolves(entries);
|
|
518
542
|
|
|
519
|
-
const result = await ctx.service.teardownPackage(
|
|
543
|
+
const result = await ctx.service.teardownPackage(
|
|
544
|
+
"my-environment",
|
|
545
|
+
"pkg",
|
|
546
|
+
);
|
|
520
547
|
|
|
521
548
|
expect(result.dropped).toHaveLength(2);
|
|
522
549
|
expect(result.errors).toHaveLength(0);
|
|
@@ -543,14 +570,14 @@ describe("MaterializationService", () => {
|
|
|
543
570
|
throw new Error(`unknown connection: ${name}`);
|
|
544
571
|
},
|
|
545
572
|
};
|
|
546
|
-
(ctx.
|
|
573
|
+
(ctx.environmentStore.getEnvironment as sinon.SinonStub).resolves({
|
|
547
574
|
getPackage: sinon.stub().resolves(pkg),
|
|
548
575
|
});
|
|
549
576
|
ctx.repository.getActiveMaterialization.resolves(null);
|
|
550
577
|
const entries: ManifestEntry[] = [
|
|
551
578
|
{
|
|
552
579
|
id: "entry-ghost",
|
|
553
|
-
|
|
580
|
+
environmentId: "proj-1",
|
|
554
581
|
packageName: "pkg",
|
|
555
582
|
buildId: "abcdef1234567890abcdef1234567890",
|
|
556
583
|
tableName: "table_ghost",
|
|
@@ -562,7 +589,10 @@ describe("MaterializationService", () => {
|
|
|
562
589
|
];
|
|
563
590
|
(ctx.manifestService.listEntries as sinon.SinonStub).resolves(entries);
|
|
564
591
|
|
|
565
|
-
const result = await ctx.service.teardownPackage(
|
|
592
|
+
const result = await ctx.service.teardownPackage(
|
|
593
|
+
"my-environment",
|
|
594
|
+
"pkg",
|
|
595
|
+
);
|
|
566
596
|
|
|
567
597
|
expect(result.dropped).toHaveLength(1);
|
|
568
598
|
expect(result.dropped[0].targetDropSkipped).toBe(true);
|
|
@@ -586,13 +616,13 @@ describe("MaterializationService", () => {
|
|
|
586
616
|
throw new Error(`unknown connection: ${name}`);
|
|
587
617
|
},
|
|
588
618
|
};
|
|
589
|
-
(ctx.
|
|
619
|
+
(ctx.environmentStore.getEnvironment as sinon.SinonStub).resolves({
|
|
590
620
|
getPackage: sinon.stub().resolves(pkg),
|
|
591
621
|
});
|
|
592
622
|
ctx.repository.getActiveMaterialization.resolves(null);
|
|
593
623
|
const entry: ManifestEntry = {
|
|
594
624
|
id: "entry-1",
|
|
595
|
-
|
|
625
|
+
environmentId: "proj-1",
|
|
596
626
|
packageName: "pkg",
|
|
597
627
|
buildId: "abcdef1234567890abcdef1234567890",
|
|
598
628
|
tableName: "orphan",
|
|
@@ -603,9 +633,13 @@ describe("MaterializationService", () => {
|
|
|
603
633
|
};
|
|
604
634
|
(ctx.manifestService.listEntries as sinon.SinonStub).resolves([entry]);
|
|
605
635
|
|
|
606
|
-
const result = await ctx.service.teardownPackage(
|
|
607
|
-
|
|
608
|
-
|
|
636
|
+
const result = await ctx.service.teardownPackage(
|
|
637
|
+
"my-environment",
|
|
638
|
+
"pkg",
|
|
639
|
+
{
|
|
640
|
+
dryRun: true,
|
|
641
|
+
},
|
|
642
|
+
);
|
|
609
643
|
|
|
610
644
|
expect(result.dropped).toHaveLength(1);
|
|
611
645
|
expect(result.dropped[0].tableName).toBe("orphan");
|