@malloy-publisher/server 0.0.87 → 0.0.89
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/build.ts +26 -0
- package/dist/app/api-doc.yaml +126 -5
- package/dist/app/assets/RenderedResult-BAZuT25g-QakVAbYy.js +2 -0
- package/dist/app/assets/{index-BbW5TZg_.js → index-Bq29VQqL.js} +2 -2
- package/dist/app/assets/{index-2xWCh-ya.css → index-CcIq0aEZ.css} +1 -1
- package/dist/app/assets/index-DZMePHJ5.js +251 -0
- package/dist/app/assets/{index-CIfV3yj1.js → index-TslDWlxH.js} +6 -6
- package/dist/app/assets/{index.umd-x-naS8R7.js → index.umd-BN4_E5KD.js} +259 -259
- package/dist/app/assets/mui-BEbinrI-.js +161 -0
- package/dist/app/assets/vendor-c5ypKtDW.js +17 -0
- package/dist/app/index.html +4 -2
- package/dist/instrumentation.js +67818 -35196
- package/dist/server.js +80404 -82231
- package/package.json +11 -5
- package/publisher.config.json +1 -1
- package/src/config.ts +20 -0
- package/src/constants.ts +14 -0
- package/src/controller/connection.controller.ts +21 -4
- package/src/controller/package.controller.ts +52 -2
- package/src/controller/schedule.controller.ts +3 -3
- package/src/controller/watch-mode.controller.ts +83 -0
- package/src/errors.ts +2 -1
- package/src/logger.ts +9 -0
- package/src/server.ts +33 -19
- package/src/service/connection.ts +159 -161
- package/src/service/model.ts +6 -6
- package/src/service/package.spec.ts +12 -10
- package/src/service/package.ts +15 -8
- package/src/service/project.ts +77 -36
- package/src/service/project_store.spec.ts +83 -56
- package/src/service/project_store.ts +330 -50
- package/src/utils.ts +0 -18
- package/tests/harness/mcp_test_setup.ts +5 -5
- package/dist/app/assets/RenderedResult-BAZuT25g-BMU632YI.js +0 -2
- package/dist/app/assets/index-C7whj6wK.js +0 -432
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { PostgresConnection } from "@malloydata/db-postgres";
|
|
2
1
|
import { BigQueryConnection } from "@malloydata/db-bigquery";
|
|
2
|
+
import { MySQLConnection } from "@malloydata/db-mysql";
|
|
3
|
+
import { PostgresConnection } from "@malloydata/db-postgres";
|
|
3
4
|
import { SnowflakeConnection } from "@malloydata/db-snowflake";
|
|
4
5
|
import { TrinoConnection } from "@malloydata/db-trino";
|
|
5
|
-
import { MySQLConnection } from "@malloydata/db-mysql";
|
|
6
|
-
import { v4 as uuidv4 } from "uuid";
|
|
7
6
|
import { Connection } from "@malloydata/malloy";
|
|
8
|
-
import { components } from "../api";
|
|
9
|
-
import path from "path";
|
|
10
|
-
import fs from "fs/promises";
|
|
11
|
-
import { CONNECTIONS_MANIFEST_NAME } from "../utils";
|
|
12
7
|
import { BaseConnection } from "@malloydata/malloy/connection";
|
|
8
|
+
import fs from "fs/promises";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { v4 as uuidv4 } from "uuid";
|
|
11
|
+
import { components } from "../api";
|
|
12
|
+
import { CONNECTIONS_MANIFEST_NAME } from "../constants";
|
|
13
|
+
import { logger } from "../logger";
|
|
13
14
|
|
|
14
15
|
type ApiConnection = components["schemas"]["Connection"];
|
|
15
16
|
type ApiConnectionAttributes = components["schemas"]["ConnectionAttributes"];
|
|
@@ -42,184 +43,181 @@ export async function readConnectionConfig(
|
|
|
42
43
|
return JSON.parse(connectionFileContents.toString()) as ApiConnection[];
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
export async function createConnections(
|
|
46
|
+
export async function createConnections(
|
|
47
|
+
basePath: string,
|
|
48
|
+
defaultConnections: ApiConnection[] = [],
|
|
49
|
+
): Promise<{
|
|
46
50
|
malloyConnections: Map<string, BaseConnection>;
|
|
47
51
|
apiConnections: InternalConnection[];
|
|
48
52
|
}> {
|
|
49
53
|
const connectionMap = new Map<string, BaseConnection>();
|
|
50
54
|
const connectionConfig = await readConnectionConfig(basePath);
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
for (const connection of [...defaultConnections, ...connectionConfig]) {
|
|
57
|
+
logger.info(`Adding connection ${connection.name}`, {
|
|
58
|
+
connection,
|
|
59
|
+
});
|
|
60
|
+
// This case shouldn't happen. The package validation logic should
|
|
61
|
+
// catch it.
|
|
62
|
+
if (!connection.name) {
|
|
63
|
+
throw "Invalid connection configuration. No name.";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
switch (connection.type) {
|
|
67
|
+
case "postgres": {
|
|
68
|
+
const configReader = async () => {
|
|
69
|
+
if (!connection.postgresConnection) {
|
|
70
|
+
throw "Invalid connection configuration. No postgres connection.";
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
host: connection.postgresConnection.host,
|
|
74
|
+
port: connection.postgresConnection.port,
|
|
75
|
+
username: connection.postgresConnection.userName,
|
|
76
|
+
password: connection.postgresConnection.password,
|
|
77
|
+
databaseName: connection.postgresConnection.databaseName,
|
|
78
|
+
connectionString:
|
|
79
|
+
connection.postgresConnection.connectionString,
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
const postgresConnection = new PostgresConnection(
|
|
83
|
+
connection.name,
|
|
84
|
+
() => ({}),
|
|
85
|
+
configReader,
|
|
86
|
+
);
|
|
87
|
+
connectionMap.set(connection.name, postgresConnection);
|
|
88
|
+
connection.attributes = getConnectionAttributes(postgresConnection);
|
|
89
|
+
break;
|
|
58
90
|
}
|
|
59
91
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (!connection.postgresConnection) {
|
|
64
|
-
throw "Invalid connection configuration. No postgres connection.";
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
host: connection.postgresConnection.host,
|
|
68
|
-
port: connection.postgresConnection.port,
|
|
69
|
-
username: connection.postgresConnection.userName,
|
|
70
|
-
password: connection.postgresConnection.password,
|
|
71
|
-
databaseName: connection.postgresConnection.databaseName,
|
|
72
|
-
connectionString:
|
|
73
|
-
connection.postgresConnection.connectionString,
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
const postgresConnection = new PostgresConnection(
|
|
77
|
-
connection.name,
|
|
78
|
-
() => ({}),
|
|
79
|
-
configReader,
|
|
80
|
-
);
|
|
81
|
-
connectionMap.set(connection.name, postgresConnection);
|
|
82
|
-
connection.attributes =
|
|
83
|
-
getConnectionAttributes(postgresConnection);
|
|
84
|
-
break;
|
|
92
|
+
case "mysql": {
|
|
93
|
+
if (!connection.mysqlConnection) {
|
|
94
|
+
throw "Invalid connection configuration. No mysql connection.";
|
|
85
95
|
}
|
|
96
|
+
const config = {
|
|
97
|
+
host: connection.mysqlConnection.host,
|
|
98
|
+
port: connection.mysqlConnection.port,
|
|
99
|
+
user: connection.mysqlConnection.user,
|
|
100
|
+
password: connection.mysqlConnection.password,
|
|
101
|
+
database: connection.mysqlConnection.database,
|
|
102
|
+
};
|
|
103
|
+
const mysqlConnection = new MySQLConnection(
|
|
104
|
+
connection.name,
|
|
105
|
+
config,
|
|
106
|
+
);
|
|
107
|
+
connectionMap.set(connection.name, mysqlConnection);
|
|
108
|
+
connection.attributes = getConnectionAttributes(mysqlConnection);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
86
111
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
const config = {
|
|
92
|
-
host: connection.mysqlConnection.host,
|
|
93
|
-
port: connection.mysqlConnection.port,
|
|
94
|
-
user: connection.mysqlConnection.user,
|
|
95
|
-
password: connection.mysqlConnection.password,
|
|
96
|
-
database: connection.mysqlConnection.database,
|
|
97
|
-
};
|
|
98
|
-
const mysqlConnection = new MySQLConnection(
|
|
99
|
-
connection.name,
|
|
100
|
-
config,
|
|
101
|
-
);
|
|
102
|
-
connectionMap.set(connection.name, mysqlConnection);
|
|
103
|
-
connection.attributes = getConnectionAttributes(mysqlConnection);
|
|
104
|
-
break;
|
|
112
|
+
case "bigquery": {
|
|
113
|
+
if (!connection.bigqueryConnection) {
|
|
114
|
+
throw "Invalid connection configuration. No bigquery connection.";
|
|
105
115
|
}
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
serviceAccountKeyPath
|
|
117
|
-
|
|
118
|
-
`${connection.name}-${uuidv4()}-service-account-key.json`,
|
|
119
|
-
);
|
|
120
|
-
await fs.writeFile(
|
|
121
|
-
serviceAccountKeyPath,
|
|
122
|
-
connection.bigqueryConnection
|
|
123
|
-
.serviceAccountKeyJson as string,
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const bigqueryConnectionOptions = {
|
|
128
|
-
projectId: connection.bigqueryConnection.defaultProjectId,
|
|
129
|
-
serviceAccountKeyPath: serviceAccountKeyPath,
|
|
130
|
-
location: connection.bigqueryConnection.location,
|
|
131
|
-
maximumBytesBilled:
|
|
132
|
-
connection.bigqueryConnection.maximumBytesBilled,
|
|
133
|
-
timeoutMs:
|
|
134
|
-
connection.bigqueryConnection.queryTimeoutMilliseconds,
|
|
135
|
-
billingProjectId:
|
|
136
|
-
connection.bigqueryConnection.billingProjectId,
|
|
137
|
-
};
|
|
138
|
-
const bigqueryConnection = new BigQueryConnection(
|
|
139
|
-
connection.name,
|
|
140
|
-
() => ({}),
|
|
141
|
-
bigqueryConnectionOptions,
|
|
117
|
+
// If a service account key file is provided, we persist it to disk
|
|
118
|
+
// and pass the path to the BigQueryConnection.
|
|
119
|
+
let serviceAccountKeyPath = undefined;
|
|
120
|
+
if (connection.bigqueryConnection.serviceAccountKeyJson) {
|
|
121
|
+
serviceAccountKeyPath = path.join(
|
|
122
|
+
"/tmp",
|
|
123
|
+
`${connection.name}-${uuidv4()}-service-account-key.json`,
|
|
124
|
+
);
|
|
125
|
+
await fs.writeFile(
|
|
126
|
+
serviceAccountKeyPath,
|
|
127
|
+
connection.bigqueryConnection.serviceAccountKeyJson as string,
|
|
142
128
|
);
|
|
143
|
-
connectionMap.set(connection.name, bigqueryConnection);
|
|
144
|
-
connection.attributes =
|
|
145
|
-
getConnectionAttributes(bigqueryConnection);
|
|
146
|
-
break;
|
|
147
129
|
}
|
|
148
130
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
131
|
+
const bigqueryConnectionOptions = {
|
|
132
|
+
projectId: connection.bigqueryConnection.defaultProjectId,
|
|
133
|
+
serviceAccountKeyPath: serviceAccountKeyPath,
|
|
134
|
+
location: connection.bigqueryConnection.location,
|
|
135
|
+
maximumBytesBilled:
|
|
136
|
+
connection.bigqueryConnection.maximumBytesBilled,
|
|
137
|
+
timeoutMs:
|
|
138
|
+
connection.bigqueryConnection.queryTimeoutMilliseconds,
|
|
139
|
+
billingProjectId: connection.bigqueryConnection.billingProjectId,
|
|
140
|
+
};
|
|
141
|
+
const bigqueryConnection = new BigQueryConnection(
|
|
142
|
+
connection.name,
|
|
143
|
+
() => ({}),
|
|
144
|
+
bigqueryConnectionOptions,
|
|
145
|
+
);
|
|
146
|
+
connectionMap.set(connection.name, bigqueryConnection);
|
|
147
|
+
connection.attributes = getConnectionAttributes(bigqueryConnection);
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
162
150
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
151
|
+
case "snowflake": {
|
|
152
|
+
if (!connection.snowflakeConnection) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
"Snowflake connection configuration is missing.",
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
if (!connection.snowflakeConnection.account) {
|
|
158
|
+
throw new Error("Snowflake account is required.");
|
|
159
|
+
}
|
|
166
160
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
161
|
+
if (!connection.snowflakeConnection.username) {
|
|
162
|
+
throw new Error("Snowflake username is required.");
|
|
163
|
+
}
|
|
170
164
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
account: connection.snowflakeConnection.account,
|
|
174
|
-
username: connection.snowflakeConnection.username,
|
|
175
|
-
password: connection.snowflakeConnection.password,
|
|
176
|
-
warehouse: connection.snowflakeConnection.warehouse,
|
|
177
|
-
database: connection.snowflakeConnection.database,
|
|
178
|
-
schema: connection.snowflakeConnection.schema,
|
|
179
|
-
timeout:
|
|
180
|
-
connection.snowflakeConnection
|
|
181
|
-
.responseTimeoutMilliseconds,
|
|
182
|
-
},
|
|
183
|
-
};
|
|
184
|
-
const snowflakeConnection = new SnowflakeConnection(
|
|
185
|
-
connection.name,
|
|
186
|
-
snowflakeConnectionOptions,
|
|
187
|
-
);
|
|
188
|
-
connectionMap.set(connection.name, snowflakeConnection);
|
|
189
|
-
connection.attributes =
|
|
190
|
-
getConnectionAttributes(snowflakeConnection);
|
|
191
|
-
break;
|
|
165
|
+
if (!connection.snowflakeConnection.password) {
|
|
166
|
+
throw new Error("Snowflake password is required.");
|
|
192
167
|
}
|
|
193
168
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
throw new Error("Trino connection configuration is missing.");
|
|
197
|
-
}
|
|
198
|
-
const trinoConnectionOptions = {
|
|
199
|
-
server: connection.trinoConnection.server,
|
|
200
|
-
port: connection.trinoConnection.port,
|
|
201
|
-
catalog: connection.trinoConnection.catalog,
|
|
202
|
-
schema: connection.trinoConnection.schema,
|
|
203
|
-
user: connection.trinoConnection.user,
|
|
204
|
-
password: connection.trinoConnection.password,
|
|
205
|
-
};
|
|
206
|
-
const trinoConnection = new TrinoConnection(
|
|
207
|
-
connection.name,
|
|
208
|
-
{},
|
|
209
|
-
trinoConnectionOptions,
|
|
210
|
-
);
|
|
211
|
-
connectionMap.set(connection.name, trinoConnection);
|
|
212
|
-
connection.attributes = getConnectionAttributes(trinoConnection);
|
|
213
|
-
break;
|
|
169
|
+
if (!connection.snowflakeConnection.warehouse) {
|
|
170
|
+
throw new Error("Snowflake warehouse is required.");
|
|
214
171
|
}
|
|
215
172
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
173
|
+
const snowflakeConnectionOptions = {
|
|
174
|
+
connOptions: {
|
|
175
|
+
account: connection.snowflakeConnection.account,
|
|
176
|
+
username: connection.snowflakeConnection.username,
|
|
177
|
+
password: connection.snowflakeConnection.password,
|
|
178
|
+
warehouse: connection.snowflakeConnection.warehouse,
|
|
179
|
+
database: connection.snowflakeConnection.database,
|
|
180
|
+
schema: connection.snowflakeConnection.schema,
|
|
181
|
+
timeout:
|
|
182
|
+
connection.snowflakeConnection.responseTimeoutMilliseconds,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
const snowflakeConnection = new SnowflakeConnection(
|
|
186
|
+
connection.name,
|
|
187
|
+
snowflakeConnectionOptions,
|
|
188
|
+
);
|
|
189
|
+
connectionMap.set(connection.name, snowflakeConnection);
|
|
190
|
+
connection.attributes =
|
|
191
|
+
getConnectionAttributes(snowflakeConnection);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
case "trino": {
|
|
196
|
+
if (!connection.trinoConnection) {
|
|
197
|
+
throw new Error("Trino connection configuration is missing.");
|
|
220
198
|
}
|
|
199
|
+
const trinoConnectionOptions = {
|
|
200
|
+
server: connection.trinoConnection.server,
|
|
201
|
+
port: connection.trinoConnection.port,
|
|
202
|
+
catalog: connection.trinoConnection.catalog,
|
|
203
|
+
schema: connection.trinoConnection.schema,
|
|
204
|
+
user: connection.trinoConnection.user,
|
|
205
|
+
password: connection.trinoConnection.password,
|
|
206
|
+
};
|
|
207
|
+
const trinoConnection = new TrinoConnection(
|
|
208
|
+
connection.name,
|
|
209
|
+
{},
|
|
210
|
+
trinoConnectionOptions,
|
|
211
|
+
);
|
|
212
|
+
connectionMap.set(connection.name, trinoConnection);
|
|
213
|
+
connection.attributes = getConnectionAttributes(trinoConnection);
|
|
214
|
+
break;
|
|
221
215
|
}
|
|
222
|
-
|
|
216
|
+
|
|
217
|
+
default: {
|
|
218
|
+
throw new Error(`Unsupported connection type: ${connection.type}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
223
221
|
}
|
|
224
222
|
|
|
225
223
|
return {
|
package/src/service/model.ts
CHANGED
|
@@ -25,6 +25,11 @@ import { metrics } from "@opentelemetry/api";
|
|
|
25
25
|
import * as fs from "fs/promises";
|
|
26
26
|
import * as path from "path";
|
|
27
27
|
import { components } from "../api";
|
|
28
|
+
import {
|
|
29
|
+
MODEL_FILE_SUFFIX,
|
|
30
|
+
NOTEBOOK_FILE_SUFFIX,
|
|
31
|
+
ROW_LIMIT,
|
|
32
|
+
} from "../constants";
|
|
28
33
|
import { HackyDataStylesAccumulator } from "../data_styles";
|
|
29
34
|
import {
|
|
30
35
|
BadRequestError,
|
|
@@ -32,12 +37,7 @@ import {
|
|
|
32
37
|
ModelNotFoundError,
|
|
33
38
|
} from "../errors";
|
|
34
39
|
import { logger } from "../logger";
|
|
35
|
-
import {
|
|
36
|
-
MODEL_FILE_SUFFIX,
|
|
37
|
-
NOTEBOOK_FILE_SUFFIX,
|
|
38
|
-
ROW_LIMIT,
|
|
39
|
-
URL_READER,
|
|
40
|
-
} from "../utils";
|
|
40
|
+
import { URL_READER } from "../utils";
|
|
41
41
|
|
|
42
42
|
type ApiCompiledModel = components["schemas"]["CompiledModel"];
|
|
43
43
|
type ApiNotebookCell = components["schemas"]["NotebookCell"];
|
|
@@ -4,13 +4,18 @@ import { join } from "path";
|
|
|
4
4
|
import sinon from "sinon";
|
|
5
5
|
import { PackageNotFoundError } from "../errors";
|
|
6
6
|
import { readConnectionConfig } from "./connection";
|
|
7
|
-
import { Model } from "./model";
|
|
7
|
+
import { ApiConnection, Model } from "./model";
|
|
8
8
|
import { Package } from "./package";
|
|
9
9
|
import { Scheduler } from "./scheduler";
|
|
10
10
|
|
|
11
11
|
// Minimal partial types for mocking
|
|
12
12
|
type PartialScheduler = Pick<Scheduler, "list">;
|
|
13
13
|
|
|
14
|
+
const connectionMocks: ApiConnection[] = [
|
|
15
|
+
{ name: "conn1", type: "postgres", postgresConnection: {} },
|
|
16
|
+
{ name: "conn2", type: "bigquery", bigqueryConnection: {} },
|
|
17
|
+
];
|
|
18
|
+
|
|
14
19
|
describe("service/package", () => {
|
|
15
20
|
const testPackageDirectory = "testPackage";
|
|
16
21
|
|
|
@@ -24,10 +29,7 @@ describe("service/package", () => {
|
|
|
24
29
|
join(testPackageDirectory, "database.csv"),
|
|
25
30
|
parquetBuffer,
|
|
26
31
|
);
|
|
27
|
-
const content = JSON.stringify(
|
|
28
|
-
{ name: "conn1", type: "database" },
|
|
29
|
-
{ name: "conn2", type: "api" },
|
|
30
|
-
]);
|
|
32
|
+
const content = JSON.stringify(connectionMocks);
|
|
31
33
|
await fs.writeFile(
|
|
32
34
|
join(testPackageDirectory, "publisher.connections.json"),
|
|
33
35
|
content,
|
|
@@ -82,7 +84,7 @@ describe("service/package", () => {
|
|
|
82
84
|
});
|
|
83
85
|
it("should return a Package object if the package exists", async () => {
|
|
84
86
|
sinon.stub(fs, "stat").resolves();
|
|
85
|
-
sinon
|
|
87
|
+
const readFileStub = sinon
|
|
86
88
|
.stub(fs, "readFile")
|
|
87
89
|
.resolves(
|
|
88
90
|
Buffer.from(JSON.stringify({ description: "Test package" })),
|
|
@@ -98,6 +100,9 @@ describe("service/package", () => {
|
|
|
98
100
|
list: () => [],
|
|
99
101
|
} as PartialScheduler);
|
|
100
102
|
|
|
103
|
+
readFileStub.restore();
|
|
104
|
+
readFileStub.resolves(Buffer.from(JSON.stringify([])));
|
|
105
|
+
|
|
101
106
|
const packageInstance = await Package.create(
|
|
102
107
|
"testProject",
|
|
103
108
|
"testPackage",
|
|
@@ -221,10 +226,7 @@ describe("service/package", () => {
|
|
|
221
226
|
sinon.stub(fs, "stat").resolves();
|
|
222
227
|
const config = await readConnectionConfig(testPackageDirectory);
|
|
223
228
|
|
|
224
|
-
expect(config).toEqual(
|
|
225
|
-
{ name: "conn1", type: "database" },
|
|
226
|
-
{ name: "conn2", type: "api" },
|
|
227
|
-
]);
|
|
229
|
+
expect(config).toEqual(connectionMocks);
|
|
228
230
|
});
|
|
229
231
|
});
|
|
230
232
|
});
|
package/src/service/package.ts
CHANGED
|
@@ -11,14 +11,14 @@ import {
|
|
|
11
11
|
import { metrics } from "@opentelemetry/api";
|
|
12
12
|
import recursive from "recursive-readdir";
|
|
13
13
|
import { components } from "../api";
|
|
14
|
-
import { API_PREFIX } from "../constants";
|
|
15
|
-
import { PackageNotFoundError } from "../errors";
|
|
16
|
-
import { logger } from "../logger";
|
|
17
14
|
import {
|
|
15
|
+
API_PREFIX,
|
|
18
16
|
MODEL_FILE_SUFFIX,
|
|
19
17
|
NOTEBOOK_FILE_SUFFIX,
|
|
20
18
|
PACKAGE_MANIFEST_NAME,
|
|
21
|
-
} from "../
|
|
19
|
+
} from "../constants";
|
|
20
|
+
import { PackageNotFoundError } from "../errors";
|
|
21
|
+
import { logger } from "../logger";
|
|
22
22
|
import { createConnections } from "./connection";
|
|
23
23
|
import { Model } from "./model";
|
|
24
24
|
import { Scheduler } from "./scheduler";
|
|
@@ -101,7 +101,10 @@ export class Package {
|
|
|
101
101
|
unit: "ms",
|
|
102
102
|
});
|
|
103
103
|
const connections = new Map<string, Connection>(projectConnections);
|
|
104
|
-
|
|
104
|
+
logger.info(`Project connections: ${connections.size}`, {
|
|
105
|
+
connections,
|
|
106
|
+
projectConnections,
|
|
107
|
+
});
|
|
105
108
|
// Package connections override project connections.
|
|
106
109
|
const { malloyConnections: packageConnections } =
|
|
107
110
|
await createConnections(packagePath);
|
|
@@ -147,6 +150,11 @@ export class Package {
|
|
|
147
150
|
malloy_package_name: packageName,
|
|
148
151
|
status: "success",
|
|
149
152
|
});
|
|
153
|
+
logger.info(`Successfully loaded package ${packageName}`, {
|
|
154
|
+
packageName,
|
|
155
|
+
duration: executionTime,
|
|
156
|
+
unit: "ms",
|
|
157
|
+
});
|
|
150
158
|
return new Package(
|
|
151
159
|
projectName,
|
|
152
160
|
packageName,
|
|
@@ -158,15 +166,14 @@ export class Package {
|
|
|
158
166
|
);
|
|
159
167
|
} catch (error) {
|
|
160
168
|
logger.error(`Error loading package ${packageName}`, { error });
|
|
169
|
+
console.error(error);
|
|
161
170
|
const endTime = performance.now();
|
|
162
171
|
const executionTime = endTime - startTime;
|
|
163
172
|
this.packageLoadHistogram.record(executionTime, {
|
|
164
173
|
malloy_package_name: packageName,
|
|
165
174
|
status: "error",
|
|
166
175
|
});
|
|
167
|
-
throw
|
|
168
|
-
cause: error,
|
|
169
|
-
});
|
|
176
|
+
throw error;
|
|
170
177
|
}
|
|
171
178
|
}
|
|
172
179
|
|