@malloydata/db-publisher 0.0.315 → 0.0.316

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.
Files changed (32) hide show
  1. package/dist/client/api.d.ts +1594 -528
  2. package/dist/client/api.js +1820 -553
  3. package/dist/client/api.js.map +1 -1
  4. package/dist/client/base.d.ts +1 -1
  5. package/dist/client/base.js +1 -1
  6. package/dist/client/common.d.ts +1 -1
  7. package/dist/client/common.js +1 -1
  8. package/dist/client/configuration.d.ts +1 -1
  9. package/dist/client/configuration.js +1 -1
  10. package/dist/client/index.d.ts +1 -1
  11. package/dist/client/index.js +1 -1
  12. package/dist/publisher_connection.d.ts +4 -1
  13. package/dist/publisher_connection.integration.spec.js +208 -0
  14. package/dist/publisher_connection.integration.spec.js.map +1 -0
  15. package/dist/publisher_connection.js +42 -11
  16. package/dist/publisher_connection.js.map +1 -1
  17. package/dist/publisher_connection.unit.spec.d.ts +1 -0
  18. package/dist/{publisher_connection.spec.js → publisher_connection.unit.spec.js} +214 -175
  19. package/dist/publisher_connection.unit.spec.js.map +1 -0
  20. package/package.json +2 -2
  21. package/publisher-api-doc.yaml +1434 -449
  22. package/src/client/.openapi-generator/FILES +0 -1
  23. package/src/client/api.ts +2513 -754
  24. package/src/client/base.ts +1 -1
  25. package/src/client/common.ts +1 -1
  26. package/src/client/configuration.ts +1 -1
  27. package/src/client/index.ts +1 -1
  28. package/src/publisher_connection.integration.spec.ts +200 -0
  29. package/src/publisher_connection.ts +67 -19
  30. package/src/{publisher_connection.spec.ts → publisher_connection.unit.spec.ts} +260 -175
  31. package/dist/publisher_connection.spec.js.map +0 -1
  32. /package/dist/{publisher_connection.spec.d.ts → publisher_connection.integration.spec.d.ts} +0 -0
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
  /**
4
4
  * Malloy Publisher - Semantic Model Serving API
5
- * The Malloy Publisher - Semantic Model Serving API serves Malloy packages. A Malloy package is a directory of Malloy models (.malloy files), Malloy notebooks (.malloynb files), and embedded datbases (.parque files) with a malloy-publisher.json manifest at the package\'s root directory. For example, see the Malloy samples packages (https://github.com/malloydata/malloy-samples) repo.
5
+ * The Malloy Publisher - Semantic Model Serving API provides comprehensive access to Malloy packages and their associated resources. A Malloy package is a directory containing Malloy models (.malloy files), Malloy notebooks (.malloynb files), and embedded databases (.parquet files) with a malloy-publisher.json manifest at the package\'s root directory. ## Key Features - **Project Management**: Create and manage projects with their associated packages and connections - **Package Lifecycle**: Full CRUD operations for Malloy packages and their versions - **Model & Notebook Access**: Retrieve and execute Malloy models and notebooks - **Connection Management**: Secure database connection configuration and testing - **Query Execution**: Execute queries against models and retrieve results - **Watch Mode**: Real-time file watching for development workflows ## Resource Hierarchy The API follows a hierarchical resource structure: ``` Projects ├── Connections └── Packages ├── Models ├── Notebooks └── Databases ``` For examples, see the Malloy samples packages (https://github.com/malloydata/malloy-samples) repository.
6
6
  *
7
7
  * The version of the OpenAPI document: v0
8
8
  *
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
  /**
4
4
  * Malloy Publisher - Semantic Model Serving API
5
- * The Malloy Publisher - Semantic Model Serving API serves Malloy packages. A Malloy package is a directory of Malloy models (.malloy files), Malloy notebooks (.malloynb files), and embedded datbases (.parque files) with a malloy-publisher.json manifest at the package\'s root directory. For example, see the Malloy samples packages (https://github.com/malloydata/malloy-samples) repo.
5
+ * The Malloy Publisher - Semantic Model Serving API provides comprehensive access to Malloy packages and their associated resources. A Malloy package is a directory containing Malloy models (.malloy files), Malloy notebooks (.malloynb files), and embedded databases (.parquet files) with a malloy-publisher.json manifest at the package\'s root directory. ## Key Features - **Project Management**: Create and manage projects with their associated packages and connections - **Package Lifecycle**: Full CRUD operations for Malloy packages and their versions - **Model & Notebook Access**: Retrieve and execute Malloy models and notebooks - **Connection Management**: Secure database connection configuration and testing - **Query Execution**: Execute queries against models and retrieve results - **Watch Mode**: Real-time file watching for development workflows ## Resource Hierarchy The API follows a hierarchical resource structure: ``` Projects ├── Connections └── Packages ├── Models ├── Notebooks └── Databases ``` For examples, see the Malloy samples packages (https://github.com/malloydata/malloy-samples) repository.
6
6
  *
7
7
  * The version of the OpenAPI document: v0
8
8
  *
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
  /**
4
4
  * Malloy Publisher - Semantic Model Serving API
5
- * The Malloy Publisher - Semantic Model Serving API serves Malloy packages. A Malloy package is a directory of Malloy models (.malloy files), Malloy notebooks (.malloynb files), and embedded datbases (.parque files) with a malloy-publisher.json manifest at the package\'s root directory. For example, see the Malloy samples packages (https://github.com/malloydata/malloy-samples) repo.
5
+ * The Malloy Publisher - Semantic Model Serving API provides comprehensive access to Malloy packages and their associated resources. A Malloy package is a directory containing Malloy models (.malloy files), Malloy notebooks (.malloynb files), and embedded databases (.parquet files) with a malloy-publisher.json manifest at the package\'s root directory. ## Key Features - **Project Management**: Create and manage projects with their associated packages and connections - **Package Lifecycle**: Full CRUD operations for Malloy packages and their versions - **Model & Notebook Access**: Retrieve and execute Malloy models and notebooks - **Connection Management**: Secure database connection configuration and testing - **Query Execution**: Execute queries against models and retrieve results - **Watch Mode**: Real-time file watching for development workflows ## Resource Hierarchy The API follows a hierarchical resource structure: ``` Projects ├── Connections └── Packages ├── Models ├── Notebooks └── Databases ``` For examples, see the Malloy samples packages (https://github.com/malloydata/malloy-samples) repository.
6
6
  *
7
7
  * The version of the OpenAPI document: v0
8
8
  *
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable */
3
3
  /**
4
4
  * Malloy Publisher - Semantic Model Serving API
5
- * The Malloy Publisher - Semantic Model Serving API serves Malloy packages. A Malloy package is a directory of Malloy models (.malloy files), Malloy notebooks (.malloynb files), and embedded datbases (.parque files) with a malloy-publisher.json manifest at the package\'s root directory. For example, see the Malloy samples packages (https://github.com/malloydata/malloy-samples) repo.
5
+ * The Malloy Publisher - Semantic Model Serving API provides comprehensive access to Malloy packages and their associated resources. A Malloy package is a directory containing Malloy models (.malloy files), Malloy notebooks (.malloynb files), and embedded databases (.parquet files) with a malloy-publisher.json manifest at the package\'s root directory. ## Key Features - **Project Management**: Create and manage projects with their associated packages and connections - **Package Lifecycle**: Full CRUD operations for Malloy packages and their versions - **Model & Notebook Access**: Retrieve and execute Malloy models and notebooks - **Connection Management**: Secure database connection configuration and testing - **Query Execution**: Execute queries against models and retrieve results - **Watch Mode**: Real-time file watching for development workflows ## Resource Hierarchy The API follows a hierarchical resource structure: ``` Projects ├── Connections └── Packages ├── Models ├── Notebooks └── Databases ``` For examples, see the Malloy samples packages (https://github.com/malloydata/malloy-samples) repository.
6
6
  *
7
7
  * The version of the OpenAPI document: v0
8
8
  *
@@ -0,0 +1,200 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import * as malloy from '@malloydata/malloy';
9
+ import {describeIfDatabaseAvailable} from '@malloydata/malloy/test';
10
+ import {PublisherConnection} from './publisher_connection';
11
+ import {fileURLToPath} from 'url';
12
+ import * as util from 'util';
13
+ import * as fs from 'fs';
14
+
15
+ const [describe] = describeIfDatabaseAvailable(['publisher']);
16
+
17
+ describe.skip('db:Publisher Integration Tests', () => {
18
+ let conn: PublisherConnection | null;
19
+ let runtime: malloy.Runtime | null;
20
+
21
+ beforeEach(async () => {
22
+ try {
23
+ conn = await PublisherConnection.create('bq_demo', {
24
+ connectionUri:
25
+ 'http://localhost:4000/api/v0/projects/malloy-samples/connections/bq_demo',
26
+ });
27
+ const files = {
28
+ readURL: async (url: URL) => {
29
+ const filePath = fileURLToPath(url);
30
+ return await util.promisify(fs.readFile)(filePath, 'utf8');
31
+ },
32
+ };
33
+ runtime = new malloy.Runtime({
34
+ urlReader: files,
35
+ connection: conn,
36
+ });
37
+ } catch (error) {
38
+ // Skip tests if connection cannot be established
39
+ conn = null;
40
+ runtime = null;
41
+ }
42
+ });
43
+
44
+ afterEach(async () => {
45
+ if (conn) {
46
+ await conn.close();
47
+ }
48
+ });
49
+
50
+ it('tests the connection', async () => {
51
+ if (!conn) {
52
+ pending('Publisher service not available');
53
+ return;
54
+ }
55
+ await conn.test();
56
+ });
57
+
58
+ it('correctly identifies the dialect', () => {
59
+ if (!conn) {
60
+ pending('Publisher service not available');
61
+ return;
62
+ }
63
+ expect(conn.dialectName).toBe('standardsql');
64
+ });
65
+
66
+ it('correctly identifies the connection as a pooled connection', () => {
67
+ if (!conn) {
68
+ pending('Publisher service not available');
69
+ return;
70
+ }
71
+ expect(conn.isPool()).toBe(false);
72
+ });
73
+
74
+ it('correctly identifies the connection as a streaming connection', () => {
75
+ if (!conn) {
76
+ pending('Publisher service not available');
77
+ return;
78
+ }
79
+ expect(conn.canStream()).toBe(true);
80
+ });
81
+
82
+ it('correctly identifies the connection as a persistSQLResults connection', () => {
83
+ if (!conn) {
84
+ pending('Publisher service not available');
85
+ return;
86
+ }
87
+ expect(conn.canPersist()).toBe(true);
88
+ });
89
+
90
+ it('fetches the table schema', async () => {
91
+ if (!conn) {
92
+ pending('Publisher service not available');
93
+ return;
94
+ }
95
+ const schema = await conn.fetchTableSchema(
96
+ 'ecommerce_bq',
97
+ 'ecommerce_bq.users'
98
+ );
99
+ expect(schema.type).toBe('table');
100
+ expect(schema.dialect).toBe('standardsql');
101
+ expect(schema.tablePath).toBe('ecommerce_bq.users');
102
+ expect(schema.fields.length).toBe(14);
103
+ expect(schema.fields[0].name).toBe('id');
104
+ expect(schema.fields[0].type).toBe('number');
105
+ });
106
+
107
+ it('fetches the sql source schema', async () => {
108
+ if (!conn) {
109
+ pending('Publisher service not available');
110
+ return;
111
+ }
112
+ const schema = await conn.fetchSelectSchema({
113
+ connection: 'bq_demo',
114
+ selectStr: 'SELECT * FROM ecommerce_bq.users',
115
+ });
116
+ expect(schema.type).toBe('sql_select');
117
+ expect(schema.dialect).toBe('standardsql');
118
+ expect(schema.fields.length).toBe(14);
119
+ expect(schema.fields[0].name).toBe('id');
120
+ expect(schema.fields[0].type).toBe('number');
121
+ });
122
+
123
+ it('runs a SQL query', async () => {
124
+ if (!conn) {
125
+ pending('Publisher service not available');
126
+ return;
127
+ }
128
+ const res = await conn.runSQL('SELECT 1 as T');
129
+ expect(res.rows[0]['T']).toBe(1);
130
+ });
131
+
132
+ it('runs a Malloy query', async () => {
133
+ if (!conn || !runtime) {
134
+ pending('Publisher service not available');
135
+ return;
136
+ }
137
+ const sql = await runtime
138
+ .loadModel("source: users is bq_demo.table('ecommerce_bq.users')")
139
+ .loadQuery(
140
+ 'run: users -> { aggregate: cnt is count() group_by: state order_by: cnt desc limit: 10 }'
141
+ )
142
+ .getSQL();
143
+ const res = await conn.runSQL(sql);
144
+ expect(res.totalRows).toBe(10);
145
+ let total = 0;
146
+ for (const row of res.rows) {
147
+ total += +(row['cnt'] ?? 0);
148
+ }
149
+ expect(total).toBeGreaterThan(0);
150
+ });
151
+
152
+ it('runs a Malloy query on an sql source', async () => {
153
+ if (!conn || !runtime) {
154
+ pending('Publisher service not available');
155
+ return;
156
+ }
157
+ const sql = await runtime
158
+ .loadModel(
159
+ "source: users is bq_demo.sql('SELECT * FROM ecommerce_bq.users')"
160
+ )
161
+ .loadQuery(
162
+ 'run: users -> { aggregate: cnt is count() group_by: state order_by: cnt desc limit: 20 }'
163
+ )
164
+ .getSQL();
165
+ const res = await conn.runSQL(sql);
166
+ expect(res.totalRows).toBe(20);
167
+ expect(res.rows[0]['cnt']).toBeGreaterThan(0);
168
+ });
169
+
170
+ it('get temporary table name', async () => {
171
+ if (!conn) {
172
+ pending('Publisher service not available');
173
+ return;
174
+ }
175
+ const sql = 'SELECT 1 as T';
176
+ const tempTableName = await conn.manifestTemporaryTable(sql);
177
+ expect(tempTableName).toBeDefined();
178
+ expect(tempTableName.length).toBeGreaterThan(0);
179
+ });
180
+
181
+ it('estimates query cost', async () => {
182
+ if (!conn) {
183
+ pending('Publisher service not available');
184
+ return;
185
+ }
186
+ const cost = await conn.estimateQueryCost(
187
+ 'SELECT * FROM ecommerce_bq.users'
188
+ );
189
+ expect(cost).toEqual({});
190
+ });
191
+
192
+ it('closes connection', async () => {
193
+ if (!conn) {
194
+ pending('Publisher service not available');
195
+ return;
196
+ }
197
+ // close() should not throw and should return void
198
+ await expect(conn.close()).resolves.toBeUndefined();
199
+ });
200
+ });
@@ -6,7 +6,6 @@
6
6
  */
7
7
 
8
8
  import type {
9
- Connection,
10
9
  MalloyQueryData,
11
10
  PersistSQLResults,
12
11
  PooledConnection,
@@ -20,8 +19,14 @@ import type {
20
19
  TestableConnection,
21
20
  } from '@malloydata/malloy';
22
21
  import {BaseConnection} from '@malloydata/malloy/connection';
23
- import type {ConnectionAttributes, RawAxiosRequestConfig} from './client';
24
- import {Configuration, ConnectionsApi} from './client';
22
+ import type {
23
+ Column,
24
+ Connection,
25
+ ConnectionAttributes,
26
+ PostSqlsourceRequest,
27
+ RawAxiosRequestConfig,
28
+ } from './client';
29
+ import {Configuration, ConnectionsApi, ConnectionsTestApi} from './client';
25
30
 
26
31
  interface PublisherConnectionOptions {
27
32
  connectionUri: string;
@@ -39,7 +44,9 @@ export class PublisherConnection
39
44
  public readonly name: string;
40
45
  public readonly projectName: string;
41
46
  private connectionsApi: ConnectionsApi;
47
+ private connectionsTestApi: ConnectionsTestApi;
42
48
  private connectionAttributes: ConnectionAttributes;
49
+ private connectionData: Connection;
43
50
  private accessToken: string | undefined;
44
51
 
45
52
  static async create(name: string, options: PublisherConnectionOptions) {
@@ -66,16 +73,25 @@ export class PublisherConnection
66
73
  basePath: apiUrl,
67
74
  });
68
75
  const connectionsApi = new ConnectionsApi(configuration);
76
+ const connectionsTestApi = new ConnectionsTestApi(configuration);
69
77
  const response = await connectionsApi.getConnection(projectName, name, {
70
78
  headers: PublisherConnection.getAuthHeaders(options.accessToken),
71
79
  });
72
- const connectionAttributes = response.data
73
- .attributes as ConnectionAttributes;
80
+ if (!response || !response.data) {
81
+ throw new Error(
82
+ `Failed to get connection: ${name} from project: ${projectName}`
83
+ );
84
+ }
85
+ const connectionData = response.data as Connection;
86
+ const connectionAttributes =
87
+ connectionData.attributes as ConnectionAttributes;
74
88
  const connection = new PublisherConnection(
75
89
  name,
76
90
  projectName,
77
91
  connectionsApi,
92
+ connectionsTestApi,
78
93
  connectionAttributes,
94
+ connectionData,
79
95
  options.accessToken
80
96
  );
81
97
  await connection.test();
@@ -94,14 +110,18 @@ export class PublisherConnection
94
110
  name: string,
95
111
  projectName: string,
96
112
  connectionsApi: ConnectionsApi,
113
+ connectionsTestApi: ConnectionsTestApi,
97
114
  connectionAttributes: ConnectionAttributes,
115
+ connectionData: Connection,
98
116
  accessToken: string | undefined
99
117
  ) {
100
118
  super();
101
119
  this.name = name;
102
120
  this.projectName = projectName;
103
121
  this.connectionsApi = connectionsApi;
122
+ this.connectionsTestApi = connectionsTestApi;
104
123
  this.connectionAttributes = connectionAttributes;
124
+ this.connectionData = connectionData;
105
125
  this.accessToken = accessToken;
106
126
  }
107
127
 
@@ -125,25 +145,41 @@ export class PublisherConnection
125
145
  tableKey: string,
126
146
  tablePath: string
127
147
  ): Promise<TableSourceDef> {
128
- const response = await this.connectionsApi.getTablesource(
148
+ const response = await this.connectionsApi.getTable(
129
149
  this.projectName,
130
150
  this.name,
131
- tableKey,
151
+ tablePath.split('/')[0],
132
152
  tablePath,
133
153
  {
134
154
  headers: PublisherConnection.getAuthHeaders(this.accessToken),
135
155
  }
136
156
  );
137
- return JSON.parse(response.data.source as string) as TableSourceDef;
157
+ // Convert the Table response to TableSourceDef format
158
+ const tableData = response.data;
159
+ return {
160
+ type: 'table',
161
+ name: tableKey,
162
+ tablePath: tablePath,
163
+ connection: this.name,
164
+ dialect: this.dialectName,
165
+ fields:
166
+ tableData.columns?.map((col: Column) => ({
167
+ name: col.name,
168
+ type: col.type,
169
+ })) || [],
170
+ } as TableSourceDef;
138
171
  }
139
172
 
140
173
  public async fetchSelectSchema(
141
174
  sqlRef: SQLSourceRequest
142
175
  ): Promise<SQLSourceDef> {
143
- const response = await this.connectionsApi.getSqlsource(
176
+ const request: PostSqlsourceRequest = {
177
+ sqlStatement: sqlRef.selectStr,
178
+ };
179
+ const response = await this.connectionsApi.postSqlsource(
144
180
  this.projectName,
145
181
  this.name,
146
- sqlRef.selectStr,
182
+ request,
147
183
  {
148
184
  headers: PublisherConnection.getAuthHeaders(this.accessToken),
149
185
  }
@@ -162,10 +198,13 @@ export class PublisherConnection
162
198
  ): Promise<MalloyQueryData> {
163
199
  // TODO: Add support for abortSignal.
164
200
  options.abortSignal = undefined;
165
- const response = await this.connectionsApi.getQuerydata(
201
+ const request: PostSqlsourceRequest = {
202
+ sqlStatement: sql,
203
+ };
204
+ const response = await this.connectionsApi.postQuerydata(
166
205
  this.projectName,
167
206
  this.name,
168
- sql,
207
+ request,
169
208
  JSON.stringify(options),
170
209
  {
171
210
  headers: PublisherConnection.getAuthHeaders(this.accessToken),
@@ -181,10 +220,13 @@ export class PublisherConnection
181
220
  // TODO: Add support for abortSignal.
182
221
  options.abortSignal = undefined;
183
222
  // TODO: Add real streaming support to publisher API.
184
- const response = await this.connectionsApi.getQuerydata(
223
+ const request: PostSqlsourceRequest = {
224
+ sqlStatement: sqlCommand,
225
+ };
226
+ const response = await this.connectionsApi.postQuerydata(
185
227
  this.projectName,
186
228
  this.name,
187
- sqlCommand,
229
+ request,
188
230
  JSON.stringify(options),
189
231
  {
190
232
  headers: PublisherConnection.getAuthHeaders(this.accessToken),
@@ -199,16 +241,22 @@ export class PublisherConnection
199
241
  }
200
242
 
201
243
  public async test(): Promise<void> {
202
- await this.connectionsApi.getTest(this.projectName, this.name, {
203
- headers: PublisherConnection.getAuthHeaders(this.accessToken),
204
- });
244
+ await this.connectionsTestApi.testConnectionConfiguration(
245
+ this.connectionData,
246
+ {
247
+ headers: PublisherConnection.getAuthHeaders(this.accessToken),
248
+ }
249
+ );
205
250
  }
206
251
 
207
252
  public async manifestTemporaryTable(sqlCommand: string): Promise<string> {
208
- const response = await this.connectionsApi.getTemporarytable(
253
+ const request: PostSqlsourceRequest = {
254
+ sqlStatement: sqlCommand,
255
+ };
256
+ const response = await this.connectionsApi.postTemporarytable(
209
257
  this.projectName,
210
258
  this.name,
211
- sqlCommand,
259
+ request,
212
260
  {
213
261
  headers: PublisherConnection.getAuthHeaders(this.accessToken),
214
262
  }