@malloydata/malloy 0.0.240-dev250305162504 → 0.0.240-dev250305213425
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/api/sessioned.d.ts +10 -3
- package/dist/api/sessioned.js +60 -29
- package/dist/api/sessioned.spec.js +72 -13
- package/package.json +3 -3
package/dist/api/sessioned.d.ts
CHANGED
|
@@ -4,7 +4,14 @@ export type TTL = {
|
|
|
4
4
|
} | Date;
|
|
5
5
|
export interface OptionsBase {
|
|
6
6
|
ttl?: TTL;
|
|
7
|
+
session_id?: string;
|
|
7
8
|
}
|
|
8
|
-
export declare function compileModel(request: Malloy.CompileModelRequest, options?: OptionsBase): Malloy.CompileModelResponse
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
export declare function compileModel(request: Malloy.CompileModelRequest, options?: OptionsBase): Malloy.CompileModelResponse & {
|
|
10
|
+
session_id: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function compileSource(request: Malloy.CompileSourceRequest, options?: OptionsBase): Malloy.CompileSourceResponse & {
|
|
13
|
+
session_id: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function compileQuery(request: Malloy.CompileQueryRequest, options?: OptionsBase): Malloy.CompileQueryResponse & {
|
|
16
|
+
session_id: string;
|
|
17
|
+
};
|
package/dist/api/sessioned.js
CHANGED
|
@@ -32,6 +32,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
32
32
|
exports.compileQuery = exports.compileSource = exports.compileModel = void 0;
|
|
33
33
|
const Malloy = __importStar(require("@malloydata/malloy-interfaces"));
|
|
34
34
|
const Core = __importStar(require("./core"));
|
|
35
|
+
const uuid_1 = require("uuid");
|
|
35
36
|
function sessionInfosMatch(a, b) {
|
|
36
37
|
if (a.type === 'compile_model') {
|
|
37
38
|
if (b.type !== 'compile_model')
|
|
@@ -53,18 +54,23 @@ function sessionInfosMatch(a, b) {
|
|
|
53
54
|
}
|
|
54
55
|
class SessionManager {
|
|
55
56
|
constructor() {
|
|
56
|
-
this.sessions =
|
|
57
|
+
this.sessions = new Map();
|
|
57
58
|
}
|
|
58
|
-
purgeExpired(
|
|
59
|
+
purgeExpired(options) {
|
|
59
60
|
const now = new Date();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
for (const session of this.sessions.values()) {
|
|
62
|
+
if (session.sessionId === (options === null || options === void 0 ? void 0 : options.except))
|
|
63
|
+
continue;
|
|
64
|
+
if (session.expires && session.expires < now) {
|
|
65
|
+
this.sessions.delete(session.sessionId);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
63
68
|
}
|
|
64
|
-
findSession(sessionInfo) {
|
|
65
|
-
const session = this.sessions.
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
findSession(sessionId, sessionInfo) {
|
|
70
|
+
const session = this.sessions.get(sessionId);
|
|
71
|
+
if (session && sessionInfosMatch(session.sessionInfo, sessionInfo)) {
|
|
72
|
+
return session;
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
getExpires(ttl) {
|
|
70
76
|
if (ttl instanceof Date) {
|
|
@@ -75,6 +81,13 @@ class SessionManager {
|
|
|
75
81
|
return new Date(Date.now() + ttl.seconds * 1000);
|
|
76
82
|
}
|
|
77
83
|
}
|
|
84
|
+
newSessionId() {
|
|
85
|
+
let id;
|
|
86
|
+
do {
|
|
87
|
+
id = (0, uuid_1.v4)();
|
|
88
|
+
} while (this.sessions.has(id));
|
|
89
|
+
return id;
|
|
90
|
+
}
|
|
78
91
|
newCompileModelSession(request, sessionInfo, options) {
|
|
79
92
|
const expires = (options === null || options === void 0 ? void 0 : options.ttl) ? this.getExpires(options.ttl) : undefined;
|
|
80
93
|
const state = Core.newCompileModelState(request);
|
|
@@ -83,6 +96,7 @@ class SessionManager {
|
|
|
83
96
|
sessionInfo,
|
|
84
97
|
state,
|
|
85
98
|
expires,
|
|
99
|
+
sessionId: this.newSessionId(),
|
|
86
100
|
};
|
|
87
101
|
}
|
|
88
102
|
newCompileSourceSession(request, sessionInfo, options) {
|
|
@@ -93,6 +107,7 @@ class SessionManager {
|
|
|
93
107
|
sessionInfo,
|
|
94
108
|
state,
|
|
95
109
|
expires,
|
|
110
|
+
sessionId: this.newSessionId(),
|
|
96
111
|
};
|
|
97
112
|
}
|
|
98
113
|
newCompileQuerySession(request, sessionInfo, options) {
|
|
@@ -103,16 +118,17 @@ class SessionManager {
|
|
|
103
118
|
sessionInfo,
|
|
104
119
|
state,
|
|
105
120
|
expires,
|
|
121
|
+
sessionId: this.newSessionId(),
|
|
106
122
|
};
|
|
107
123
|
}
|
|
108
|
-
findCompileModelSession(sessionInfo) {
|
|
109
|
-
const session = this.findSession(sessionInfo);
|
|
124
|
+
findCompileModelSession(sessionId, sessionInfo) {
|
|
125
|
+
const session = this.findSession(sessionId, sessionInfo);
|
|
110
126
|
if ((session === null || session === void 0 ? void 0 : session.type) === 'compile_model') {
|
|
111
127
|
return session;
|
|
112
128
|
}
|
|
113
129
|
}
|
|
114
|
-
killSession(
|
|
115
|
-
this.sessions
|
|
130
|
+
killSession(sessionId) {
|
|
131
|
+
this.sessions.delete(sessionId);
|
|
116
132
|
}
|
|
117
133
|
hasErrors(log) {
|
|
118
134
|
var _a;
|
|
@@ -124,22 +140,27 @@ class SessionManager {
|
|
|
124
140
|
modelURL: request.model_url,
|
|
125
141
|
extendModelURL: request.extend_model_url,
|
|
126
142
|
};
|
|
127
|
-
let session =
|
|
143
|
+
let session = (options === null || options === void 0 ? void 0 : options.session_id) &&
|
|
144
|
+
this.findCompileModelSession(options.session_id, sessionInfo);
|
|
145
|
+
this.purgeExpired({ except: options === null || options === void 0 ? void 0 : options.session_id });
|
|
128
146
|
if (session) {
|
|
147
|
+
if (options === null || options === void 0 ? void 0 : options.ttl) {
|
|
148
|
+
session.expires = this.getExpires(options.ttl);
|
|
149
|
+
}
|
|
129
150
|
Core.updateCompileModelState(session.state, request.compiler_needs);
|
|
130
151
|
}
|
|
131
152
|
else {
|
|
132
153
|
session = this.newCompileModelSession(request, sessionInfo, options);
|
|
133
|
-
this.sessions.
|
|
154
|
+
this.sessions.set(session.sessionId, session);
|
|
134
155
|
}
|
|
135
156
|
const result = Core.statedCompileModel(session.state);
|
|
136
157
|
if (result.model || this.hasErrors(result.logs)) {
|
|
137
|
-
this.killSession(
|
|
158
|
+
this.killSession(session.sessionId);
|
|
138
159
|
}
|
|
139
|
-
return result;
|
|
160
|
+
return { ...result, session_id: session.sessionId };
|
|
140
161
|
}
|
|
141
|
-
findCompileSourceSession(sessionInfo) {
|
|
142
|
-
const session = this.findSession(sessionInfo);
|
|
162
|
+
findCompileSourceSession(sessionId, sessionInfo) {
|
|
163
|
+
const session = this.findSession(sessionId, sessionInfo);
|
|
143
164
|
if ((session === null || session === void 0 ? void 0 : session.type) === 'compile_source') {
|
|
144
165
|
return session;
|
|
145
166
|
}
|
|
@@ -151,22 +172,27 @@ class SessionManager {
|
|
|
151
172
|
name: request.name,
|
|
152
173
|
extendModelURL: request.extend_model_url,
|
|
153
174
|
};
|
|
154
|
-
let session =
|
|
175
|
+
let session = (options === null || options === void 0 ? void 0 : options.session_id) &&
|
|
176
|
+
this.findCompileSourceSession(options.session_id, sessionInfo);
|
|
177
|
+
this.purgeExpired({ except: options === null || options === void 0 ? void 0 : options.session_id });
|
|
155
178
|
if (session) {
|
|
179
|
+
if (options === null || options === void 0 ? void 0 : options.ttl) {
|
|
180
|
+
session.expires = this.getExpires(options.ttl);
|
|
181
|
+
}
|
|
156
182
|
Core.updateCompileModelState(session.state, request.compiler_needs);
|
|
157
183
|
}
|
|
158
184
|
else {
|
|
159
185
|
session = this.newCompileSourceSession(request, sessionInfo, options);
|
|
160
|
-
this.sessions.
|
|
186
|
+
this.sessions.set(session.sessionId, session);
|
|
161
187
|
}
|
|
162
188
|
const result = Core.statedCompileSource(session.state, request.name);
|
|
163
189
|
if (result.source || this.hasErrors(result.logs)) {
|
|
164
|
-
this.killSession(
|
|
190
|
+
this.killSession(session.sessionId);
|
|
165
191
|
}
|
|
166
|
-
return result;
|
|
192
|
+
return { ...result, session_id: session.sessionId };
|
|
167
193
|
}
|
|
168
|
-
findCompileQuerySession(sessionInfo) {
|
|
169
|
-
const session = this.findSession(sessionInfo);
|
|
194
|
+
findCompileQuerySession(sessionId, sessionInfo) {
|
|
195
|
+
const session = this.findSession(sessionId, sessionInfo);
|
|
170
196
|
if ((session === null || session === void 0 ? void 0 : session.type) === 'compile_query') {
|
|
171
197
|
return session;
|
|
172
198
|
}
|
|
@@ -179,19 +205,24 @@ class SessionManager {
|
|
|
179
205
|
queryString,
|
|
180
206
|
query: request.query,
|
|
181
207
|
};
|
|
182
|
-
let session =
|
|
208
|
+
let session = (options === null || options === void 0 ? void 0 : options.session_id) &&
|
|
209
|
+
this.findCompileQuerySession(options.session_id, sessionInfo);
|
|
210
|
+
this.purgeExpired({ except: options === null || options === void 0 ? void 0 : options.session_id });
|
|
183
211
|
if (session) {
|
|
212
|
+
if (options === null || options === void 0 ? void 0 : options.ttl) {
|
|
213
|
+
session.expires = this.getExpires(options.ttl);
|
|
214
|
+
}
|
|
184
215
|
Core.updateCompileModelState(session.state, request.compiler_needs);
|
|
185
216
|
}
|
|
186
217
|
else {
|
|
187
218
|
session = this.newCompileQuerySession(request, sessionInfo, options);
|
|
188
|
-
this.sessions.
|
|
219
|
+
this.sessions.set(session.sessionId, session);
|
|
189
220
|
}
|
|
190
221
|
const result = Core.statedCompileQuery(session.state);
|
|
191
222
|
if (result.result || this.hasErrors(result.logs)) {
|
|
192
|
-
this.killSession(
|
|
223
|
+
this.killSession(session.sessionId);
|
|
193
224
|
}
|
|
194
|
-
return result;
|
|
225
|
+
return { ...result, session_id: session.sessionId };
|
|
195
226
|
}
|
|
196
227
|
}
|
|
197
228
|
const SESSION_MANAGER = new SessionManager();
|
|
@@ -33,7 +33,7 @@ describe('api', () => {
|
|
|
33
33
|
},
|
|
34
34
|
],
|
|
35
35
|
},
|
|
36
|
-
});
|
|
36
|
+
}, { session_id: result.session_id });
|
|
37
37
|
expected = {
|
|
38
38
|
compiler_needs: {
|
|
39
39
|
table_schemas: [
|
|
@@ -44,6 +44,7 @@ describe('api', () => {
|
|
|
44
44
|
],
|
|
45
45
|
connections: [{ name: 'connection' }],
|
|
46
46
|
},
|
|
47
|
+
session_id: result.session_id,
|
|
47
48
|
};
|
|
48
49
|
expect(result).toMatchObject(expected);
|
|
49
50
|
result = (0, sessioned_1.compileModel)({
|
|
@@ -66,7 +67,7 @@ describe('api', () => {
|
|
|
66
67
|
],
|
|
67
68
|
connections: [{ name: 'connection', dialect: 'duckdb' }],
|
|
68
69
|
},
|
|
69
|
-
});
|
|
70
|
+
}, { session_id: result.session_id });
|
|
70
71
|
expected = {
|
|
71
72
|
model: {
|
|
72
73
|
entries: [
|
|
@@ -86,6 +87,7 @@ describe('api', () => {
|
|
|
86
87
|
],
|
|
87
88
|
anonymous_queries: [],
|
|
88
89
|
},
|
|
90
|
+
session_id: result.session_id,
|
|
89
91
|
};
|
|
90
92
|
expect(result).toMatchObject(expected);
|
|
91
93
|
});
|
|
@@ -135,7 +137,7 @@ describe('api', () => {
|
|
|
135
137
|
],
|
|
136
138
|
connections: [{ name: 'connection', dialect: 'duckdb' }],
|
|
137
139
|
},
|
|
138
|
-
});
|
|
140
|
+
}, { session_id: result.session_id });
|
|
139
141
|
expected = {
|
|
140
142
|
source: {
|
|
141
143
|
name: 'flights',
|
|
@@ -149,6 +151,7 @@ describe('api', () => {
|
|
|
149
151
|
],
|
|
150
152
|
},
|
|
151
153
|
},
|
|
154
|
+
session_id: result.session_id,
|
|
152
155
|
};
|
|
153
156
|
expect(result).toMatchObject(expected);
|
|
154
157
|
});
|
|
@@ -197,7 +200,7 @@ describe('api', () => {
|
|
|
197
200
|
},
|
|
198
201
|
],
|
|
199
202
|
},
|
|
200
|
-
});
|
|
203
|
+
}, { session_id: result.session_id });
|
|
201
204
|
expected = {
|
|
202
205
|
compiler_needs: {
|
|
203
206
|
table_schemas: [
|
|
@@ -231,7 +234,7 @@ describe('api', () => {
|
|
|
231
234
|
],
|
|
232
235
|
connections: [{ name: 'connection', dialect: 'duckdb' }],
|
|
233
236
|
},
|
|
234
|
-
});
|
|
237
|
+
}, { session_id: result.session_id });
|
|
235
238
|
expected = {
|
|
236
239
|
result: {
|
|
237
240
|
connection_name: 'connection',
|
|
@@ -251,6 +254,7 @@ ORDER BY 1 asc NULLS LAST
|
|
|
251
254
|
],
|
|
252
255
|
},
|
|
253
256
|
},
|
|
257
|
+
session_id: result.session_id,
|
|
254
258
|
};
|
|
255
259
|
expect(result).toMatchObject(expected);
|
|
256
260
|
});
|
|
@@ -264,6 +268,7 @@ ORDER BY 1 asc NULLS LAST
|
|
|
264
268
|
// This is in the past...
|
|
265
269
|
ttl: new Date(Date.now() - 1000),
|
|
266
270
|
});
|
|
271
|
+
const session_id = result.session_id;
|
|
267
272
|
let expected = {
|
|
268
273
|
compiler_needs: {
|
|
269
274
|
files: [
|
|
@@ -277,19 +282,72 @@ ORDER BY 1 asc NULLS LAST
|
|
|
277
282
|
(0, sessioned_1.compileModel)({
|
|
278
283
|
model_url: 'file://some_other_model.malloy',
|
|
279
284
|
});
|
|
280
|
-
result = (0, sessioned_1.compileModel)({
|
|
285
|
+
result = (0, sessioned_1.compileModel)({ model_url: 'file://test.malloy' }, { session_id });
|
|
286
|
+
expected = {
|
|
287
|
+
compiler_needs: {
|
|
288
|
+
files: [
|
|
289
|
+
{
|
|
290
|
+
url: 'file://test.malloy',
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
expect(result).toMatchObject(expected);
|
|
296
|
+
// New session
|
|
297
|
+
expect(result.session_id).not.toBe(session_id);
|
|
298
|
+
});
|
|
299
|
+
test('ttl should be updated if set in a subsequent request', () => {
|
|
300
|
+
let result = (0, sessioned_1.compileModel)({
|
|
281
301
|
model_url: 'file://test.malloy',
|
|
302
|
+
}, {
|
|
303
|
+
// This is in the past...
|
|
304
|
+
ttl: new Date(Date.now() - 1000),
|
|
282
305
|
});
|
|
283
|
-
|
|
306
|
+
const session_id = result.session_id;
|
|
307
|
+
let expected = {
|
|
308
|
+
compiler_needs: {
|
|
309
|
+
files: [
|
|
310
|
+
{
|
|
311
|
+
url: 'file://test.malloy',
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
expect(result).toMatchObject(expected);
|
|
317
|
+
result = (0, sessioned_1.compileModel)({
|
|
318
|
+
model_url: 'file://test.malloy',
|
|
284
319
|
compiler_needs: {
|
|
285
320
|
files: [
|
|
286
321
|
{
|
|
287
322
|
url: 'file://test.malloy',
|
|
323
|
+
contents: 'source: flights is connection.table("flights")',
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
},
|
|
327
|
+
}, {
|
|
328
|
+
session_id,
|
|
329
|
+
// Update TTL to be far in the future
|
|
330
|
+
ttl: { seconds: 100000 },
|
|
331
|
+
});
|
|
332
|
+
expected = {
|
|
333
|
+
compiler_needs: {
|
|
334
|
+
table_schemas: [
|
|
335
|
+
{
|
|
336
|
+
connection_name: 'connection',
|
|
337
|
+
name: 'flights',
|
|
288
338
|
},
|
|
289
339
|
],
|
|
340
|
+
connections: [{ name: 'connection' }],
|
|
290
341
|
},
|
|
342
|
+
session_id,
|
|
291
343
|
};
|
|
292
344
|
expect(result).toMatchObject(expected);
|
|
345
|
+
// Now asking for a different file should NOT purge the original session
|
|
346
|
+
(0, sessioned_1.compileModel)({
|
|
347
|
+
model_url: 'file://some_other_model.malloy',
|
|
348
|
+
});
|
|
349
|
+
result = (0, sessioned_1.compileModel)({ model_url: 'file://test.malloy' }, { session_id });
|
|
350
|
+
expect(result).toMatchObject(expected);
|
|
293
351
|
});
|
|
294
352
|
});
|
|
295
353
|
test('getting an error should kill session', () => {
|
|
@@ -333,10 +391,9 @@ ORDER BY 1 asc NULLS LAST
|
|
|
333
391
|
},
|
|
334
392
|
],
|
|
335
393
|
};
|
|
394
|
+
const session_id = result.session_id;
|
|
336
395
|
expect(result).toMatchObject(expected);
|
|
337
|
-
result = (0, sessioned_1.compileModel)({
|
|
338
|
-
model_url: 'file://test.malloy',
|
|
339
|
-
});
|
|
396
|
+
result = (0, sessioned_1.compileModel)({ model_url: 'file://test.malloy' }, { session_id });
|
|
340
397
|
expected = {
|
|
341
398
|
compiler_needs: {
|
|
342
399
|
files: [
|
|
@@ -347,6 +404,8 @@ ORDER BY 1 asc NULLS LAST
|
|
|
347
404
|
},
|
|
348
405
|
};
|
|
349
406
|
expect(result).toMatchObject(expected);
|
|
407
|
+
// Should be a new session
|
|
408
|
+
expect(result.session_id).not.toBe(session_id);
|
|
350
409
|
});
|
|
351
410
|
test('sessions should be cleared when they successfully return a result', () => {
|
|
352
411
|
let result = (0, sessioned_1.compileModel)({
|
|
@@ -396,10 +455,9 @@ ORDER BY 1 asc NULLS LAST
|
|
|
396
455
|
anonymous_queries: [],
|
|
397
456
|
},
|
|
398
457
|
};
|
|
458
|
+
const session_id = result.session_id;
|
|
399
459
|
expect(result).toMatchObject(expected);
|
|
400
|
-
result = (0, sessioned_1.compileModel)({
|
|
401
|
-
model_url: 'file://test.malloy',
|
|
402
|
-
});
|
|
460
|
+
result = (0, sessioned_1.compileModel)({ model_url: 'file://test.malloy' }, { session_id });
|
|
403
461
|
// Compiler should not know the contents of this file anymore because the session was cleared
|
|
404
462
|
expected = {
|
|
405
463
|
compiler_needs: {
|
|
@@ -411,6 +469,7 @@ ORDER BY 1 asc NULLS LAST
|
|
|
411
469
|
},
|
|
412
470
|
};
|
|
413
471
|
expect(result).toMatchObject(expected);
|
|
472
|
+
expect(result.session_id).not.toBe(session_id);
|
|
414
473
|
});
|
|
415
474
|
});
|
|
416
475
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/malloy",
|
|
3
|
-
"version": "0.0.240-
|
|
3
|
+
"version": "0.0.240-dev250305213425",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@malloydata/malloy-interfaces": "^0.0.240-
|
|
45
|
-
"@malloydata/malloy-tag": "^0.0.240-
|
|
44
|
+
"@malloydata/malloy-interfaces": "^0.0.240-dev250305213425",
|
|
45
|
+
"@malloydata/malloy-tag": "^0.0.240-dev250305213425",
|
|
46
46
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
47
47
|
"assert": "^2.0.0",
|
|
48
48
|
"jest-diff": "^29.6.2",
|