@malloy-publisher/server 0.0.192 → 0.0.194
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 +1 -0
- package/dist/app/api-doc.yaml +558 -1
- package/dist/app/assets/{HomePage-H1OH-VW5.js → HomePage-DbZS0N7G.js} +1 -1
- package/dist/app/assets/MainPage-CBuWkbmr.js +2 -0
- package/dist/app/assets/{ModelPage-Crau5hgZ.js → ModelPage-Bt37smot.js} +1 -1
- package/dist/app/assets/{PackagePage-CbubRhgE.js → PackagePage-DLZe50WG.js} +1 -1
- package/dist/app/assets/{ProjectPage-DUlJkYJ4.js → ProjectPage-FQTEPXP4.js} +1 -1
- package/dist/app/assets/{RouteError-DrNXNihc.js → RouteError-DefbDO7F.js} +1 -1
- package/dist/app/assets/{WorkbookPage-CBBv7n5U.js → WorkbookPage-CkAo16ar.js} +1 -1
- package/dist/app/assets/{core-Dzx75uJR.es-DwnFZnyO.js → core-BrfQApxh.es-DnvCX4oH.js} +14 -14
- package/dist/app/assets/index-5eLCcNmP.css +1 -0
- package/dist/app/assets/{index-d5rvmoZ7.js → index-Bu0ub036.js} +119 -119
- package/dist/app/assets/index-CkzK3JIl.js +40 -0
- package/dist/app/assets/index-CoA6HIGS.js +1742 -0
- package/dist/app/assets/{index.umd-CetYIBQY.js → index.umd-B6Ms2PpL.js} +46 -46
- package/dist/app/index.html +2 -2
- package/dist/server.mjs +1529 -985
- package/package.json +11 -10
- package/src/config.ts +7 -2
- package/src/controller/connection.controller.ts +102 -27
- package/src/dto/connection.dto.spec.ts +55 -0
- package/src/dto/connection.dto.ts +87 -2
- package/src/server.ts +201 -2
- package/src/service/connection.spec.ts +250 -4
- package/src/service/connection.ts +328 -473
- package/src/service/connection_config.spec.ts +123 -0
- package/src/service/connection_config.ts +562 -0
- package/src/service/connection_service.spec.ts +50 -0
- package/src/service/connection_service.ts +125 -32
- package/src/service/db_utils.spec.ts +161 -0
- package/src/service/db_utils.ts +131 -0
- package/src/service/materialization_service.spec.ts +18 -12
- package/src/service/materialization_service.ts +54 -7
- package/src/service/model.ts +24 -27
- package/src/service/package.spec.ts +125 -1
- package/src/service/package.ts +86 -44
- package/src/service/project.ts +172 -94
- package/src/service/project_store.spec.ts +72 -0
- package/src/service/project_store.ts +98 -81
- package/tests/unit/duckdb/attached_databases.test.ts +1 -19
- package/dist/app/assets/MainPage-GL06aMke.js +0 -2
- package/dist/app/assets/index-CMlGQMcl.css +0 -1
- package/dist/app/assets/index-CzjyS9cx.js +0 -1276
- package/dist/app/assets/index-HHdhLUpv.js +0 -676
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloy-publisher/server",
|
|
3
3
|
"description": "Malloy Publisher Server",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.194",
|
|
5
5
|
"main": "dist/server.mjs",
|
|
6
6
|
"bin": {
|
|
7
7
|
"malloy-publisher": "dist/server.mjs"
|
|
@@ -34,15 +34,16 @@
|
|
|
34
34
|
"@azure/identity": "^4.13.0",
|
|
35
35
|
"@azure/storage-blob": "^12.26.0",
|
|
36
36
|
"@google-cloud/storage": "^7.16.0",
|
|
37
|
-
"@malloydata/db-bigquery": "^0.0.
|
|
38
|
-
"@malloydata/db-
|
|
39
|
-
"@malloydata/db-
|
|
40
|
-
"@malloydata/db-
|
|
41
|
-
"@malloydata/db-
|
|
42
|
-
"@malloydata/db-
|
|
43
|
-
"@malloydata/
|
|
44
|
-
"@malloydata/malloy
|
|
45
|
-
"@malloydata/
|
|
37
|
+
"@malloydata/db-bigquery": "^0.0.383",
|
|
38
|
+
"@malloydata/db-databricks": "^0.0.383",
|
|
39
|
+
"@malloydata/db-duckdb": "^0.0.383",
|
|
40
|
+
"@malloydata/db-mysql": "^0.0.383",
|
|
41
|
+
"@malloydata/db-postgres": "^0.0.383",
|
|
42
|
+
"@malloydata/db-snowflake": "^0.0.383",
|
|
43
|
+
"@malloydata/db-trino": "^0.0.383",
|
|
44
|
+
"@malloydata/malloy": "^0.0.383",
|
|
45
|
+
"@malloydata/malloy-sql": "^0.0.383",
|
|
46
|
+
"@malloydata/render-validator": "^0.0.383",
|
|
46
47
|
"@modelcontextprotocol/sdk": "^1.13.2",
|
|
47
48
|
"@opentelemetry/api": "^1.9.0",
|
|
48
49
|
"@opentelemetry/auto-instrumentations-node": "^0.57.0",
|
package/src/config.ts
CHANGED
|
@@ -90,9 +90,14 @@ export const getPublisherConfig = (serverRoot: string): PublisherConfig => {
|
|
|
90
90
|
const fileContent = fs.readFileSync(publisherConfigPath, "utf8");
|
|
91
91
|
rawConfig = JSON.parse(fileContent);
|
|
92
92
|
} catch (error) {
|
|
93
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
93
94
|
logger.error(
|
|
94
|
-
`Failed to parse ${
|
|
95
|
-
{
|
|
95
|
+
`Failed to parse ${publisherConfigPath}: ${message}. Using default empty config.`,
|
|
96
|
+
{
|
|
97
|
+
path: publisherConfigPath,
|
|
98
|
+
error: message,
|
|
99
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
100
|
+
},
|
|
96
101
|
);
|
|
97
102
|
return {
|
|
98
103
|
frozenConfig: false,
|
|
@@ -4,11 +4,13 @@ import { components } from "../api";
|
|
|
4
4
|
import { BadRequestError, ConnectionError } from "../errors";
|
|
5
5
|
import { logger } from "../logger";
|
|
6
6
|
import { testConnectionConfig } from "../service/connection";
|
|
7
|
+
import { validateDuckdbApiSurface } from "../service/connection_config";
|
|
7
8
|
import { ConnectionService } from "../service/connection_service";
|
|
8
9
|
import {
|
|
9
10
|
getSchemasForConnection,
|
|
10
11
|
listTablesForSchema,
|
|
11
12
|
} from "../service/db_utils";
|
|
13
|
+
import type { Project } from "../service/project";
|
|
12
14
|
import { ProjectStore } from "../service/project_store";
|
|
13
15
|
|
|
14
16
|
type ApiConnection = components["schemas"]["Connection"];
|
|
@@ -83,6 +85,23 @@ function validateAzureAttachedDatabases(connectionConfig: ApiConnection): void {
|
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
function validateAdminAuthoredConnection(
|
|
89
|
+
connectionName: string,
|
|
90
|
+
connectionConfig: ApiConnection,
|
|
91
|
+
): void {
|
|
92
|
+
if (connectionName === "duckdb" || connectionConfig.name === "duckdb") {
|
|
93
|
+
throw new BadRequestError(
|
|
94
|
+
"DuckDB connection name cannot be 'duckdb'; it is reserved for Publisher package sandboxes.",
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
validateDuckdbApiSurface(connectionConfig);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new BadRequestError((error as Error).message);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
86
105
|
export class ConnectionController {
|
|
87
106
|
private projectStore: ProjectStore;
|
|
88
107
|
private connectionService: ConnectionService;
|
|
@@ -95,28 +114,62 @@ export class ConnectionController {
|
|
|
95
114
|
* Gets the appropriate Malloy connection for a given connection name.
|
|
96
115
|
* For DuckDB connections, retrieves from package level; for others, from project level.
|
|
97
116
|
*/
|
|
117
|
+
private getApiConnectionForLookup(
|
|
118
|
+
project: Project,
|
|
119
|
+
connectionName: string,
|
|
120
|
+
): ApiConnection {
|
|
121
|
+
if (connectionName === "duckdb") {
|
|
122
|
+
return {
|
|
123
|
+
name: "duckdb",
|
|
124
|
+
type: "duckdb",
|
|
125
|
+
duckdbConnection: { attachedDatabases: [] },
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return project.getApiConnection(connectionName);
|
|
129
|
+
}
|
|
130
|
+
|
|
98
131
|
private async getMalloyConnection(
|
|
99
132
|
projectName: string,
|
|
100
133
|
connectionName: string,
|
|
134
|
+
packageName?: string,
|
|
101
135
|
): Promise<Connection> {
|
|
102
136
|
const project = await this.projectStore.getProject(projectName, false);
|
|
103
|
-
const connection = project.getApiConnection(connectionName);
|
|
104
137
|
|
|
105
|
-
//
|
|
106
|
-
|
|
138
|
+
// "duckdb" is the per-package sandbox; its rootDirectory is the
|
|
139
|
+
// package's directory. There is no project-level "duckdb" — the name is
|
|
140
|
+
// reserved at config time. So the lookup is intrinsically per-package
|
|
141
|
+
// and the caller must say which package to use.
|
|
142
|
+
if (connectionName === "duckdb") {
|
|
107
143
|
const packages = await project.listPackages();
|
|
108
144
|
if (packages.length === 0) {
|
|
109
|
-
|
|
145
|
+
// Fall through to project; this will surface the standard
|
|
146
|
+
// "connection not found" rather than silently inventing one.
|
|
147
|
+
return await project.getMalloyConnection(connectionName);
|
|
148
|
+
}
|
|
149
|
+
if (packageName) {
|
|
150
|
+
const known = packages.some((p) => p.name === packageName);
|
|
151
|
+
if (!known) {
|
|
152
|
+
throw new BadRequestError(
|
|
153
|
+
`Package "${packageName}" not found in project "${projectName}"`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
const pkg = await project.getPackage(packageName);
|
|
157
|
+
return await pkg.getMalloyConnection(connectionName);
|
|
110
158
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
159
|
+
if (packages.length === 1) {
|
|
160
|
+
const onlyPackage = packages[0].name;
|
|
161
|
+
if (!onlyPackage) {
|
|
162
|
+
throw new ConnectionError("Package name is undefined");
|
|
163
|
+
}
|
|
164
|
+
const pkg = await project.getPackage(onlyPackage);
|
|
165
|
+
return await pkg.getMalloyConnection(connectionName);
|
|
115
166
|
}
|
|
116
|
-
|
|
117
|
-
|
|
167
|
+
throw new BadRequestError(
|
|
168
|
+
`Ambiguous "duckdb" connection lookup: project "${projectName}" has multiple packages. ` +
|
|
169
|
+
`Use /projects/${projectName}/packages/{packageName}/connections/duckdb/... to disambiguate.`,
|
|
170
|
+
);
|
|
118
171
|
} else {
|
|
119
|
-
return project.getMalloyConnection(connectionName);
|
|
172
|
+
return await project.getMalloyConnection(connectionName);
|
|
120
173
|
}
|
|
121
174
|
}
|
|
122
175
|
|
|
@@ -188,33 +241,46 @@ export class ConnectionController {
|
|
|
188
241
|
return project.listApiConnections();
|
|
189
242
|
}
|
|
190
243
|
|
|
191
|
-
// Lists schemas (namespaces) available in a connection
|
|
244
|
+
// Lists schemas (namespaces) available in a connection.
|
|
245
|
+
// For "duckdb", the per-package sandbox, packageName disambiguates which
|
|
246
|
+
// package's DuckDB to browse in a multi-package project.
|
|
192
247
|
public async listSchemas(
|
|
193
248
|
projectName: string,
|
|
194
249
|
connectionName: string,
|
|
250
|
+
packageName?: string,
|
|
195
251
|
): Promise<ApiSchema[]> {
|
|
196
252
|
const project = await this.projectStore.getProject(projectName, false);
|
|
197
|
-
const connection =
|
|
253
|
+
const connection = this.getApiConnectionForLookup(
|
|
254
|
+
project,
|
|
255
|
+
connectionName,
|
|
256
|
+
);
|
|
198
257
|
const malloyConnection = await this.getMalloyConnection(
|
|
199
258
|
projectName,
|
|
200
259
|
connectionName,
|
|
260
|
+
packageName,
|
|
201
261
|
);
|
|
202
262
|
|
|
203
263
|
return getSchemasForConnection(connection, malloyConnection);
|
|
204
264
|
}
|
|
205
265
|
|
|
206
|
-
// Lists tables available in a schema. For postgres the schema is usually "public"
|
|
266
|
+
// Lists tables available in a schema. For postgres the schema is usually "public".
|
|
267
|
+
// packageName disambiguates per-package "duckdb" lookups (see listSchemas).
|
|
207
268
|
public async listTables(
|
|
208
269
|
projectName: string,
|
|
209
270
|
connectionName: string,
|
|
210
271
|
schemaName: string,
|
|
211
272
|
tableNames?: string[],
|
|
273
|
+
packageName?: string,
|
|
212
274
|
): Promise<ApiTable[]> {
|
|
213
275
|
const project = await this.projectStore.getProject(projectName, false);
|
|
214
|
-
const connection =
|
|
276
|
+
const connection = this.getApiConnectionForLookup(
|
|
277
|
+
project,
|
|
278
|
+
connectionName,
|
|
279
|
+
);
|
|
215
280
|
const malloyConnection = await this.getMalloyConnection(
|
|
216
281
|
projectName,
|
|
217
282
|
connectionName,
|
|
283
|
+
packageName,
|
|
218
284
|
);
|
|
219
285
|
|
|
220
286
|
return listTablesForSchema(
|
|
@@ -229,10 +295,12 @@ export class ConnectionController {
|
|
|
229
295
|
projectName: string,
|
|
230
296
|
connectionName: string,
|
|
231
297
|
sqlStatement: string,
|
|
298
|
+
packageName?: string,
|
|
232
299
|
): Promise<ApiSqlSource> {
|
|
233
300
|
const malloyConnection = await this.getMalloyConnection(
|
|
234
301
|
projectName,
|
|
235
302
|
connectionName,
|
|
303
|
+
packageName,
|
|
236
304
|
);
|
|
237
305
|
try {
|
|
238
306
|
const schema = await (
|
|
@@ -265,14 +333,19 @@ export class ConnectionController {
|
|
|
265
333
|
connectionName: string,
|
|
266
334
|
schemaName: string,
|
|
267
335
|
tablePath: string,
|
|
336
|
+
packageName?: string,
|
|
268
337
|
): Promise<ApiTable> {
|
|
269
338
|
const malloyConnection = await this.getMalloyConnection(
|
|
270
339
|
projectName,
|
|
271
340
|
connectionName,
|
|
341
|
+
packageName,
|
|
272
342
|
);
|
|
273
343
|
// Use getApiConnection to get the unwrapped ApiConnection config, consistent with listSchemas and listTables.
|
|
274
344
|
const project = await this.projectStore.getProject(projectName, false);
|
|
275
|
-
const connection =
|
|
345
|
+
const connection = this.getApiConnectionForLookup(
|
|
346
|
+
project,
|
|
347
|
+
connectionName,
|
|
348
|
+
);
|
|
276
349
|
|
|
277
350
|
// TODO: Move this database connection logic to the db_utils.ts file -- and
|
|
278
351
|
// ultimately into a connection-specific class.
|
|
@@ -346,10 +419,12 @@ export class ConnectionController {
|
|
|
346
419
|
connectionName: string,
|
|
347
420
|
sqlStatement: string,
|
|
348
421
|
options: string,
|
|
422
|
+
packageName?: string,
|
|
349
423
|
): Promise<ApiQueryData> {
|
|
350
424
|
const malloyConnection = await this.getMalloyConnection(
|
|
351
425
|
projectName,
|
|
352
426
|
connectionName,
|
|
427
|
+
packageName,
|
|
353
428
|
);
|
|
354
429
|
|
|
355
430
|
let runSQLOptions: RunSQLOptions = {};
|
|
@@ -377,10 +452,12 @@ export class ConnectionController {
|
|
|
377
452
|
projectName: string,
|
|
378
453
|
connectionName: string,
|
|
379
454
|
sqlStatement: string,
|
|
455
|
+
packageName?: string,
|
|
380
456
|
): Promise<ApiTemporaryTable> {
|
|
381
457
|
const malloyConnection = await this.getMalloyConnection(
|
|
382
458
|
projectName,
|
|
383
459
|
connectionName,
|
|
460
|
+
packageName,
|
|
384
461
|
);
|
|
385
462
|
|
|
386
463
|
try {
|
|
@@ -397,17 +474,13 @@ export class ConnectionController {
|
|
|
397
474
|
}
|
|
398
475
|
|
|
399
476
|
public async testConnectionConfiguration(
|
|
400
|
-
|
|
477
|
+
input: ApiConnection & { config?: ApiConnection },
|
|
401
478
|
): Promise<ApiConnectionStatus> {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
) {
|
|
408
|
-
connectionConfig = (connectionConfig as Record<string, unknown>)
|
|
409
|
-
.config as ApiConnection;
|
|
410
|
-
}
|
|
479
|
+
// Some clients wrap the payload as { config: <connection> }; unwrap.
|
|
480
|
+
const connectionConfig: ApiConnection =
|
|
481
|
+
input.config && typeof input.config === "object"
|
|
482
|
+
? input.config
|
|
483
|
+
: input;
|
|
411
484
|
|
|
412
485
|
if (
|
|
413
486
|
!connectionConfig ||
|
|
@@ -453,6 +526,7 @@ export class ConnectionController {
|
|
|
453
526
|
}
|
|
454
527
|
|
|
455
528
|
validateAzureAttachedDatabases(connectionConfig);
|
|
529
|
+
validateAdminAuthoredConnection(connectionName, connectionConfig);
|
|
456
530
|
|
|
457
531
|
logger.info(
|
|
458
532
|
`Creating connection "${connectionName}" in project "${projectName}"`,
|
|
@@ -478,7 +552,8 @@ export class ConnectionController {
|
|
|
478
552
|
throw new BadRequestError("Connection payload is required");
|
|
479
553
|
}
|
|
480
554
|
|
|
481
|
-
validateAzureAttachedDatabases(connection
|
|
555
|
+
validateAzureAttachedDatabases(connection);
|
|
556
|
+
validateAdminAuthoredConnection(connectionName, connection);
|
|
482
557
|
|
|
483
558
|
logger.info(
|
|
484
559
|
`Updating connection "${connectionName}" in project "${projectName}"`,
|
|
@@ -5,6 +5,7 @@ import { validate } from "class-validator";
|
|
|
5
5
|
import {
|
|
6
6
|
BigqueryConnectionDto,
|
|
7
7
|
ConnectionDto,
|
|
8
|
+
DatabricksConnectionDto,
|
|
8
9
|
PostgresConnectionDto,
|
|
9
10
|
SnowflakeConnectionDto,
|
|
10
11
|
MysqlConnectionDto,
|
|
@@ -82,9 +83,13 @@ describe("dto/connection", () => {
|
|
|
82
83
|
account: "my-account",
|
|
83
84
|
username: "user",
|
|
84
85
|
password: "pass",
|
|
86
|
+
privateKey:
|
|
87
|
+
"-----BEGIN PRIVATE KEY-----\\nabc\\n-----END PRIVATE KEY-----",
|
|
88
|
+
privateKeyPass: "secret",
|
|
85
89
|
warehouse: "my-warehouse",
|
|
86
90
|
database: "my-database",
|
|
87
91
|
schema: "my-schema",
|
|
92
|
+
role: "analyst",
|
|
88
93
|
responseTimeoutMilliseconds: 5000,
|
|
89
94
|
};
|
|
90
95
|
const snowflakeConnection = plainToInstance(
|
|
@@ -96,6 +101,56 @@ describe("dto/connection", () => {
|
|
|
96
101
|
expect(errors).toHaveLength(0);
|
|
97
102
|
});
|
|
98
103
|
|
|
104
|
+
it("should validate a valid DatabricksConnection object", async () => {
|
|
105
|
+
const validData = {
|
|
106
|
+
host: "dbc-xxxxxxxx-xxxx.cloud.databricks.com",
|
|
107
|
+
path: "/sql/1.0/warehouses/abc123",
|
|
108
|
+
token: "dapiXXXX",
|
|
109
|
+
oauthClientId: "client-id",
|
|
110
|
+
oauthClientSecret: "client-secret",
|
|
111
|
+
defaultCatalog: "main",
|
|
112
|
+
defaultSchema: "default",
|
|
113
|
+
setupSQL: "USE CATALOG main",
|
|
114
|
+
};
|
|
115
|
+
const databricksConnection = plainToInstance(
|
|
116
|
+
DatabricksConnectionDto,
|
|
117
|
+
validData,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const errors = await validate(databricksConnection);
|
|
121
|
+
expect(errors).toHaveLength(0);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should return errors for invalid DatabricksConnection object", async () => {
|
|
125
|
+
const invalidData = {
|
|
126
|
+
host: 123, // Invalid type
|
|
127
|
+
path: false, // Invalid type
|
|
128
|
+
};
|
|
129
|
+
const databricksConnection = plainToInstance(
|
|
130
|
+
DatabricksConnectionDto,
|
|
131
|
+
invalidData,
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const errors = await validate(databricksConnection);
|
|
135
|
+
expect(errors).toHaveLength(2);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should validate a valid Connection object with databricks type", async () => {
|
|
139
|
+
const validData = {
|
|
140
|
+
name: "My Databricks Connection",
|
|
141
|
+
type: "databricks",
|
|
142
|
+
databricksConnection: {
|
|
143
|
+
host: "dbc-xxxxxxxx-xxxx.cloud.databricks.com",
|
|
144
|
+
path: "/sql/1.0/warehouses/abc123",
|
|
145
|
+
token: "dapiXXXX",
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
const connection = plainToInstance(ConnectionDto, validData);
|
|
149
|
+
|
|
150
|
+
const errors = await validate(connection);
|
|
151
|
+
expect(errors).toHaveLength(0);
|
|
152
|
+
});
|
|
153
|
+
|
|
99
154
|
it("should validate a valid Connection object with postgres type", async () => {
|
|
100
155
|
const validData = {
|
|
101
156
|
name: "My Postgres Connection",
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { Type } from "class-transformer";
|
|
2
2
|
import {
|
|
3
3
|
IsEnum,
|
|
4
|
+
IsArray,
|
|
4
5
|
IsNumber,
|
|
5
6
|
IsOptional,
|
|
6
7
|
IsString,
|
|
7
8
|
ValidateNested,
|
|
8
9
|
} from "class-validator";
|
|
9
10
|
import "reflect-metadata";
|
|
11
|
+
import { components } from "../api";
|
|
10
12
|
import { ApiConnection } from "../service/model";
|
|
11
13
|
|
|
14
|
+
type AttachedDatabase = components["schemas"]["AttachedDatabase"];
|
|
15
|
+
|
|
12
16
|
export class PostgresConnectionDto {
|
|
13
17
|
@IsOptional()
|
|
14
18
|
@IsString()
|
|
@@ -96,6 +100,14 @@ export class SnowflakeConnectionDto {
|
|
|
96
100
|
@IsString()
|
|
97
101
|
password?: string;
|
|
98
102
|
|
|
103
|
+
@IsOptional()
|
|
104
|
+
@IsString()
|
|
105
|
+
privateKey?: string;
|
|
106
|
+
|
|
107
|
+
@IsOptional()
|
|
108
|
+
@IsString()
|
|
109
|
+
privateKeyPass?: string;
|
|
110
|
+
|
|
99
111
|
@IsOptional()
|
|
100
112
|
@IsString()
|
|
101
113
|
warehouse?: string;
|
|
@@ -108,11 +120,49 @@ export class SnowflakeConnectionDto {
|
|
|
108
120
|
@IsString()
|
|
109
121
|
schema?: string;
|
|
110
122
|
|
|
123
|
+
@IsOptional()
|
|
124
|
+
@IsString()
|
|
125
|
+
role?: string;
|
|
126
|
+
|
|
111
127
|
@IsOptional()
|
|
112
128
|
@IsNumber()
|
|
113
129
|
responseTimeoutMilliseconds?: number;
|
|
114
130
|
}
|
|
115
131
|
|
|
132
|
+
export class DatabricksConnectionDto {
|
|
133
|
+
@IsOptional()
|
|
134
|
+
@IsString()
|
|
135
|
+
host?: string;
|
|
136
|
+
|
|
137
|
+
@IsOptional()
|
|
138
|
+
@IsString()
|
|
139
|
+
path?: string;
|
|
140
|
+
|
|
141
|
+
@IsOptional()
|
|
142
|
+
@IsString()
|
|
143
|
+
token?: string;
|
|
144
|
+
|
|
145
|
+
@IsOptional()
|
|
146
|
+
@IsString()
|
|
147
|
+
oauthClientId?: string;
|
|
148
|
+
|
|
149
|
+
@IsOptional()
|
|
150
|
+
@IsString()
|
|
151
|
+
oauthClientSecret?: string;
|
|
152
|
+
|
|
153
|
+
@IsOptional()
|
|
154
|
+
@IsString()
|
|
155
|
+
defaultCatalog?: string;
|
|
156
|
+
|
|
157
|
+
@IsOptional()
|
|
158
|
+
@IsString()
|
|
159
|
+
defaultSchema?: string;
|
|
160
|
+
|
|
161
|
+
@IsOptional()
|
|
162
|
+
@IsString()
|
|
163
|
+
setupSQL?: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
116
166
|
export class TrinoConnectionDto {
|
|
117
167
|
@IsOptional()
|
|
118
168
|
@IsString()
|
|
@@ -143,14 +193,39 @@ export class TrinoConnectionDto {
|
|
|
143
193
|
peakaKey?: string;
|
|
144
194
|
}
|
|
145
195
|
|
|
196
|
+
export class DuckdbConnectionDto {
|
|
197
|
+
@IsOptional()
|
|
198
|
+
@IsArray()
|
|
199
|
+
attachedDatabases?: AttachedDatabase[];
|
|
200
|
+
}
|
|
201
|
+
|
|
146
202
|
export class ConnectionDto implements ApiConnection {
|
|
147
203
|
@IsOptional()
|
|
148
204
|
@IsString()
|
|
149
205
|
name?: string;
|
|
150
206
|
|
|
151
207
|
@IsOptional()
|
|
152
|
-
@IsEnum([
|
|
153
|
-
|
|
208
|
+
@IsEnum([
|
|
209
|
+
"postgres",
|
|
210
|
+
"bigquery",
|
|
211
|
+
"snowflake",
|
|
212
|
+
"trino",
|
|
213
|
+
"databricks",
|
|
214
|
+
"mysql",
|
|
215
|
+
"duckdb",
|
|
216
|
+
"motherduck",
|
|
217
|
+
"ducklake",
|
|
218
|
+
])
|
|
219
|
+
type?:
|
|
220
|
+
| "postgres"
|
|
221
|
+
| "bigquery"
|
|
222
|
+
| "snowflake"
|
|
223
|
+
| "trino"
|
|
224
|
+
| "databricks"
|
|
225
|
+
| "mysql"
|
|
226
|
+
| "duckdb"
|
|
227
|
+
| "motherduck"
|
|
228
|
+
| "ducklake";
|
|
154
229
|
|
|
155
230
|
@IsOptional()
|
|
156
231
|
@ValidateNested()
|
|
@@ -171,4 +246,14 @@ export class ConnectionDto implements ApiConnection {
|
|
|
171
246
|
@ValidateNested()
|
|
172
247
|
@Type(() => TrinoConnectionDto)
|
|
173
248
|
TrinoConnection?: TrinoConnectionDto;
|
|
249
|
+
|
|
250
|
+
@IsOptional()
|
|
251
|
+
@ValidateNested()
|
|
252
|
+
@Type(() => DatabricksConnectionDto)
|
|
253
|
+
databricksConnection?: DatabricksConnectionDto;
|
|
254
|
+
|
|
255
|
+
@IsOptional()
|
|
256
|
+
@ValidateNested()
|
|
257
|
+
@Type(() => DuckdbConnectionDto)
|
|
258
|
+
duckdbConnection?: DuckdbConnectionDto;
|
|
174
259
|
}
|