@malloydata/malloy 0.0.295 → 0.0.297

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.
@@ -45,16 +45,20 @@ exports.compileQuery = compileQuery;
45
45
  exports.runQuery = runQuery;
46
46
  const Core = __importStar(require("./core"));
47
47
  const util_1 = require("./util");
48
+ const timing_1 = require("../timing");
48
49
  async function fetchNeeds(needs, fetchers) {
49
50
  var _a, _b, _c, _d, _e, _f, _g;
50
51
  var _h, _j;
52
+ const timer = new timing_1.Timer('fetch_needs');
51
53
  if (needs === undefined) {
52
54
  throw new Error("Expected compiler to have needs because it didn't return a result");
53
55
  }
54
56
  const result = {};
55
57
  if (needs.connections) {
56
58
  for (const connection of needs.connections) {
59
+ const t = new timing_1.Timer('lookup_connection');
57
60
  const info = await fetchers.connections.lookupConnection(connection.name);
61
+ timer.contribute([t.stop()]);
58
62
  (_a = result.connections) !== null && _a !== void 0 ? _a : (result.connections = []);
59
63
  result.connections.push({
60
64
  ...connection,
@@ -65,7 +69,9 @@ async function fetchNeeds(needs, fetchers) {
65
69
  if (needs.files) {
66
70
  for (const file of needs.files) {
67
71
  // TODO handle checking if the cache has the file...
72
+ const t = new timing_1.Timer('read_url');
68
73
  const info = await fetchers.urls.readURL(new URL(file.url));
74
+ timer.contribute([t.stop()]);
69
75
  (_b = result.files) !== null && _b !== void 0 ? _b : (result.files = []);
70
76
  if (typeof info === 'string') {
71
77
  result.files.push({
@@ -89,12 +95,16 @@ async function fetchNeeds(needs, fetchers) {
89
95
  tableSchemasByConnection[tableSchema.connection_name].push(tableSchema);
90
96
  }
91
97
  for (const connectionName in tableSchemasByConnection) {
98
+ const t1 = new timing_1.Timer('lookup_connection');
92
99
  const connection = await fetchers.connections.lookupConnection(connectionName);
100
+ timer.contribute([t1.stop()]);
93
101
  const tableNames = tableSchemasByConnection[connectionName].map(t => t.name);
102
+ const t2 = new timing_1.Timer('fetch_table_schemas');
94
103
  const schemas = await Promise.all(tableNames.map(async (tableName) => ({
95
104
  name: tableName,
96
105
  schema: await connection.fetchSchemaForTable(tableName),
97
106
  })));
107
+ timer.contribute([t2.stop()]);
98
108
  (_e = result.table_schemas) !== null && _e !== void 0 ? _e : (result.table_schemas = []);
99
109
  for (const schema of schemas) {
100
110
  result.table_schemas.push({
@@ -112,12 +122,16 @@ async function fetchNeeds(needs, fetchers) {
112
122
  sqlSchemasByConnectionName[sqlSchema.connection_name].push(sqlSchema);
113
123
  }
114
124
  for (const connectionName in sqlSchemasByConnectionName) {
125
+ const t1 = new timing_1.Timer('lookup_connection');
115
126
  const connection = await fetchers.connections.lookupConnection(connectionName);
127
+ timer.contribute([t1.stop()]);
116
128
  const sqlQueries = sqlSchemasByConnectionName[connectionName].map(t => t.sql);
129
+ const t2 = new timing_1.Timer('lookup_sql_schemas');
117
130
  const schemas = await Promise.all(sqlQueries.map(async (sql) => ({
118
131
  sql,
119
132
  schema: await connection.fetchSchemaForSQLQuery(sql),
120
133
  })));
134
+ timer.contribute([t2.stop()]);
121
135
  (_g = result.sql_schemas) !== null && _g !== void 0 ? _g : (result.sql_schemas = []);
122
136
  for (const schema of schemas) {
123
137
  result.sql_schemas.push({
@@ -128,49 +142,60 @@ async function fetchNeeds(needs, fetchers) {
128
142
  }
129
143
  }
130
144
  }
131
- return result;
145
+ return { needs: result, timingInfo: timer.stop() };
132
146
  }
133
147
  async function compileModel(request, fetchers) {
148
+ const timer = new timing_1.Timer('compile_model');
134
149
  const state = Core.newCompileModelState(request);
135
150
  // eslint-disable-next-line no-constant-condition
136
151
  while (true) {
137
152
  const result = Core.statedCompileModel(state);
153
+ timer.incorporate(result.timing_info);
138
154
  if (result.model || Core.hasErrors(result.logs)) {
139
- return result;
155
+ return { ...result, timing_info: timer.stop() };
140
156
  }
141
- const needs = await fetchNeeds(result.compiler_needs, fetchers);
157
+ const { needs, timingInfo } = await fetchNeeds(result.compiler_needs, fetchers);
158
+ timer.incorporate(timingInfo);
142
159
  Core.updateCompileModelState(state, needs);
143
160
  }
144
161
  }
145
162
  async function compileSource(request, fetchers) {
163
+ const timer = new timing_1.Timer('compile_source');
146
164
  const state = Core.newCompileSourceState(request);
147
165
  // eslint-disable-next-line no-constant-condition
148
166
  while (true) {
149
167
  const result = Core.statedCompileSource(state, request.name);
168
+ timer.incorporate(result.timing_info);
150
169
  if (result.source || Core.hasErrors(result.logs)) {
151
- return result;
170
+ return { ...result, timing_info: timer.stop() };
152
171
  }
153
- const needs = await fetchNeeds(result.compiler_needs, fetchers);
172
+ const { needs, timingInfo } = await fetchNeeds(result.compiler_needs, fetchers);
173
+ timer.incorporate(timingInfo);
154
174
  Core.updateCompileModelState(state, needs);
155
175
  }
156
176
  }
157
177
  async function compileQuery(request, fetchers) {
178
+ const timer = new timing_1.Timer('compile_query');
158
179
  const state = Core.newCompileQueryState(request);
159
180
  // eslint-disable-next-line no-constant-condition
160
181
  while (true) {
161
182
  const result = Core.statedCompileQuery(state);
183
+ timer.incorporate(result.timing_info);
162
184
  if (result.result || Core.hasErrors(result.logs)) {
163
- return result;
185
+ return { ...result, timing_info: timer.stop() };
164
186
  }
165
- const needs = await fetchNeeds(result.compiler_needs, fetchers);
187
+ const { needs, timingInfo } = await fetchNeeds(result.compiler_needs, fetchers);
188
+ timer.incorporate(timingInfo);
166
189
  Core.updateCompileModelState(state, needs);
167
190
  }
168
191
  }
169
192
  async function runQuery(request, fetchers) {
170
193
  var _a, _b;
194
+ const timer = new timing_1.Timer('run_query');
171
195
  const compiled = await compileQuery(request, fetchers);
196
+ timer.incorporate(compiled.timing_info);
172
197
  if (compiled.result === undefined) {
173
- return compiled;
198
+ return { ...compiled, timing_info: timer.stop() };
174
199
  }
175
200
  const defaultURL = request.model_url;
176
201
  if (compiled.result.sql === undefined) {
@@ -187,14 +212,19 @@ async function runQuery(request, fetchers) {
187
212
  };
188
213
  }
189
214
  try {
215
+ const t1 = new timing_1.Timer('lookup_connection');
190
216
  const connection = await fetchers.connections.lookupConnection(compiled.result.connection_name);
217
+ timer.contribute([t1.stop()]);
218
+ const t2 = new timing_1.Timer('run_sql');
191
219
  const data = await connection.runSQL(compiled.result.sql, compiled.result.schema);
220
+ timer.contribute([t2.stop()]);
192
221
  return {
193
222
  ...compiled,
194
223
  result: {
195
224
  ...compiled.result,
196
225
  data,
197
226
  },
227
+ timing_info: timer.stop(),
198
228
  };
199
229
  }
200
230
  catch (error) {
@@ -209,6 +239,7 @@ async function runQuery(request, fetchers) {
209
239
  range: util_1.DEFAULT_LOG_RANGE,
210
240
  },
211
241
  ],
242
+ timing_info: timer.stop(),
212
243
  };
213
244
  }
214
245
  }
@@ -7,16 +7,19 @@ export type CompileResponse = {
7
7
  modelDef: ModelDef;
8
8
  compilerNeeds?: undefined;
9
9
  logs?: LogMessage[];
10
+ timingInfo: Malloy.TimingInfo;
10
11
  } | {
11
12
  model?: undefined;
12
13
  modelDef?: undefined;
13
14
  compilerNeeds: Malloy.CompilerNeeds;
14
15
  logs?: LogMessage[];
16
+ timingInfo: Malloy.TimingInfo;
15
17
  } | {
16
18
  model?: undefined;
17
19
  modelDef?: undefined;
18
20
  compilerNeeds?: undefined;
19
21
  logs: LogMessage[];
22
+ timingInfo: Malloy.TimingInfo;
20
23
  };
21
24
  export declare function compileQuery(request: Malloy.CompileQueryRequest, state?: CompileQueryState): Malloy.CompileQueryResponse;
22
25
  export interface CompileModelState {
package/dist/api/core.js CHANGED
@@ -59,6 +59,7 @@ const sql_block_1 = require("../model/sql_block");
59
59
  const annotation_1 = require("../annotation");
60
60
  const malloy_tag_1 = require("@malloydata/malloy-tag");
61
61
  const util_1 = require("./util");
62
+ const timing_1 = require("../timing");
62
63
  // TODO find where this should go...
63
64
  function tableKey(connectionName, tablePath) {
64
65
  return `${connectionName}:${tablePath}`;
@@ -299,12 +300,15 @@ function statedCompileSource(state, name) {
299
300
  return extractSource(_statedCompileModel(state), name, state.translator.sourceURL);
300
301
  }
301
302
  function _statedCompileModel(state) {
303
+ const timer = new timing_1.Timer('compile_model');
302
304
  let extendingModel = undefined;
305
+ let extendingResult = undefined;
303
306
  if (state.extending) {
304
307
  if (!state.extending.done) {
305
- const extendingResult = _statedCompileModel(state.extending);
308
+ extendingResult = _statedCompileModel(state.extending);
309
+ timer.contribute([extendingResult.timingInfo]);
306
310
  if (!state.extending.done) {
307
- return extendingResult;
311
+ return { ...extendingResult, timingInfo: timer.stop() };
308
312
  }
309
313
  }
310
314
  extendingModel = state.extending.translator.modelDef;
@@ -312,15 +316,20 @@ function _statedCompileModel(state) {
312
316
  if (!state.hasSource) {
313
317
  return {
314
318
  compilerNeeds: convertCompilerNeeds(undefined, [state.translator.sourceURL], undefined),
319
+ timingInfo: timer.stop(),
315
320
  };
316
321
  }
317
322
  const result = state.translator.translate(extendingModel);
323
+ timer.incorporate(result.timingInfo);
318
324
  if (result.final) {
319
325
  state.done = true;
326
+ const timingInfo = timer.stop();
320
327
  if (result.modelDef) {
328
+ const model = (0, to_stable_1.modelDefToModelInfo)(result.modelDef);
321
329
  return {
322
- model: (0, to_stable_1.modelDefToModelInfo)(result.modelDef),
330
+ model,
323
331
  modelDef: result.modelDef,
332
+ timingInfo,
324
333
  };
325
334
  }
326
335
  else {
@@ -329,18 +338,24 @@ function _statedCompileModel(state) {
329
338
  }
330
339
  return {
331
340
  logs: result.problems,
341
+ timingInfo,
332
342
  };
333
343
  }
334
344
  }
335
345
  else {
336
346
  const compilerNeeds = convertCompilerNeeds(result.compileSQL, result.urls, result.tables);
337
- return { compilerNeeds, logs: result.problems };
347
+ const timingInfo = timer.stop();
348
+ return { compilerNeeds, logs: result.problems, timingInfo };
338
349
  }
339
350
  }
340
351
  function wrapResponse(response, defaultURL) {
341
352
  const logs = response.logs ? (0, util_1.mapLogs)(response.logs, defaultURL) : undefined;
342
353
  if (response.compilerNeeds) {
343
- return { compiler_needs: response.compilerNeeds, logs };
354
+ return {
355
+ compiler_needs: response.compilerNeeds,
356
+ logs,
357
+ timing_info: response.timingInfo,
358
+ };
344
359
  }
345
360
  else {
346
361
  let translations = undefined;
@@ -352,7 +367,12 @@ function wrapResponse(response, defaultURL) {
352
367
  },
353
368
  ];
354
369
  }
355
- return { model: response.model, logs, translations };
370
+ return {
371
+ model: response.model,
372
+ logs,
373
+ translations,
374
+ timing_info: response.timingInfo,
375
+ };
356
376
  }
357
377
  }
358
378
  function _compileModel(modelURL, compilerNeeds, extendURL, state) {
@@ -383,12 +403,17 @@ function extractSource(result, name, defaultURL) {
383
403
  range: util_1.DEFAULT_LOG_RANGE,
384
404
  },
385
405
  ],
406
+ timing_info: result.timingInfo,
386
407
  };
387
408
  }
388
- return { source, logs };
409
+ return { source, logs, timing_info: result.timingInfo };
389
410
  }
390
411
  else {
391
- return { compiler_needs: result.compilerNeeds, logs };
412
+ return {
413
+ compiler_needs: result.compilerNeeds,
414
+ logs,
415
+ timing_info: result.timingInfo,
416
+ };
392
417
  }
393
418
  }
394
419
  function hasErrors(log) {
@@ -416,7 +441,9 @@ function newCompileQueryState(request) {
416
441
  }
417
442
  function statedCompileQuery(state) {
418
443
  var _a, _b;
444
+ const timer = new timing_1.Timer('compile_query');
419
445
  const result = _statedCompileModel(state);
446
+ timer.incorporate(result.timingInfo);
420
447
  // TODO this can expose the internal URL... is there a better way to handle URL-less errors from the compiler?
421
448
  const defaultURL = state.translator.sourceURL;
422
449
  const logs = result.logs ? (0, util_1.mapLogs)(result.logs, defaultURL) : undefined;
@@ -424,6 +451,7 @@ function statedCompileQuery(state) {
424
451
  const queries = result.modelDef.queryList;
425
452
  if (queries.length === 0) {
426
453
  return {
454
+ timing_info: timer.stop(),
427
455
  logs: [
428
456
  ...(logs !== null && logs !== void 0 ? logs : []),
429
457
  {
@@ -440,10 +468,12 @@ function statedCompileQuery(state) {
440
468
  const schema = result.model.anonymous_queries[index].schema;
441
469
  const annotations = (_a = result.model.anonymous_queries[index].annotations) !== null && _a !== void 0 ? _a : [];
442
470
  try {
471
+ const sqlTimer = new timing_1.Timer('generate_sql');
443
472
  const queryModel = new model_1.QueryModel(result.modelDef);
444
473
  const translatedQuery = queryModel.compileQuery(query, {
445
474
  defaultRowLimit: state.defaultRowLimit,
446
475
  });
476
+ timer.contribute([sqlTimer.stop()]);
447
477
  const modelAnnotations = (0, annotation_1.annotationToTaglines)(result.modelDef.annotation).map(l => ({
448
478
  value: l,
449
479
  }));
@@ -486,6 +516,7 @@ function statedCompileQuery(state) {
486
516
  .toString(),
487
517
  });
488
518
  }
519
+ const timingInfo = timer.stop();
489
520
  return {
490
521
  result: {
491
522
  sql: translatedQuery.sql,
@@ -497,9 +528,11 @@ function statedCompileQuery(state) {
497
528
  source_annotations: annotationsOrUndefined(sourceAnnotations),
498
529
  },
499
530
  default_row_limit_added: translatedQuery.defaultRowLimitAdded,
531
+ timing_info: timingInfo,
500
532
  };
501
533
  }
502
534
  catch (error) {
535
+ const timingInfo = timer.stop();
503
536
  return {
504
537
  logs: [
505
538
  ...(logs !== null && logs !== void 0 ? logs : []),
@@ -510,11 +543,16 @@ function statedCompileQuery(state) {
510
543
  range: util_1.DEFAULT_LOG_RANGE,
511
544
  },
512
545
  ],
546
+ timing_info: timingInfo,
513
547
  };
514
548
  }
515
549
  }
516
550
  else {
517
- return { compiler_needs: result.compilerNeeds, logs };
551
+ return {
552
+ compiler_needs: result.compilerNeeds,
553
+ logs,
554
+ timing_info: timer.stop(),
555
+ };
518
556
  }
519
557
  }
520
558
  function annotationsOrUndefined(annotations) {
@@ -45,6 +45,7 @@ exports.compileQuery = compileQuery;
45
45
  const Malloy = __importStar(require("@malloydata/malloy-interfaces"));
46
46
  const Core = __importStar(require("./core"));
47
47
  const uuid_1 = require("uuid");
48
+ const timing_1 = require("../timing");
48
49
  function sessionInfosMatch(a, b) {
49
50
  if (a.type === 'compile_model') {
50
51
  if (b.type !== 'compile_model')
@@ -109,6 +110,7 @@ class SessionManager {
109
110
  state,
110
111
  expires,
111
112
  sessionId: this.newSessionId(),
113
+ timer: new timing_1.Timer('compile_model'),
112
114
  };
113
115
  }
114
116
  newCompileSourceSession(request, sessionInfo, options) {
@@ -120,6 +122,7 @@ class SessionManager {
120
122
  state,
121
123
  expires,
122
124
  sessionId: this.newSessionId(),
125
+ timer: new timing_1.Timer('compile_source'),
123
126
  };
124
127
  }
125
128
  newCompileQuerySession(request, sessionInfo, options) {
@@ -131,6 +134,7 @@ class SessionManager {
131
134
  state,
132
135
  expires,
133
136
  sessionId: this.newSessionId(),
137
+ timer: new timing_1.Timer('compile_query'),
134
138
  };
135
139
  }
136
140
  findCompileModelSession(sessionId, sessionInfo) {
@@ -155,6 +159,10 @@ class SessionManager {
155
159
  this.findCompileModelSession(options.session_id, sessionInfo);
156
160
  this.purgeExpired({ except: options === null || options === void 0 ? void 0 : options.session_id });
157
161
  if (session) {
162
+ if (session.waitingTimer) {
163
+ session.timer.contribute([session.waitingTimer.stop()]);
164
+ session.waitingTimer = undefined;
165
+ }
158
166
  if (options === null || options === void 0 ? void 0 : options.ttl) {
159
167
  session.expires = this.getExpires(options.ttl);
160
168
  }
@@ -165,10 +173,21 @@ class SessionManager {
165
173
  this.sessions.set(session.sessionId, session);
166
174
  }
167
175
  const result = Core.statedCompileModel(session.state);
168
- if (result.model || this.hasErrors(result.logs)) {
176
+ session.timer.incorporate(result.timing_info);
177
+ const done = result.model || this.hasErrors(result.logs);
178
+ if (done) {
169
179
  this.killSession(session.sessionId);
170
180
  }
171
- return { ...result, session_id: session.sessionId };
181
+ // TODO not really using it as "stop", but more like "current"
182
+ const timingInfo = session.timer.stop();
183
+ if (!done) {
184
+ session.waitingTimer = new timing_1.Timer('session_wait');
185
+ }
186
+ return {
187
+ ...result,
188
+ session_id: session.sessionId,
189
+ timing_info: timingInfo,
190
+ };
172
191
  }
173
192
  findCompileSourceSession(sessionId, sessionInfo) {
174
193
  const session = this.findSession(sessionId, sessionInfo);
@@ -187,6 +206,10 @@ class SessionManager {
187
206
  this.findCompileSourceSession(options.session_id, sessionInfo);
188
207
  this.purgeExpired({ except: options === null || options === void 0 ? void 0 : options.session_id });
189
208
  if (session) {
209
+ if (session.waitingTimer) {
210
+ session.timer.contribute([session.waitingTimer.stop()]);
211
+ session.waitingTimer = undefined;
212
+ }
190
213
  if (options === null || options === void 0 ? void 0 : options.ttl) {
191
214
  session.expires = this.getExpires(options.ttl);
192
215
  }
@@ -197,10 +220,20 @@ class SessionManager {
197
220
  this.sessions.set(session.sessionId, session);
198
221
  }
199
222
  const result = Core.statedCompileSource(session.state, request.name);
200
- if (result.source || this.hasErrors(result.logs)) {
223
+ session.timer.incorporate(result.timing_info);
224
+ const done = result.source || this.hasErrors(result.logs);
225
+ if (done) {
201
226
  this.killSession(session.sessionId);
202
227
  }
203
- return { ...result, session_id: session.sessionId };
228
+ const timingInfo = session.timer.stop();
229
+ if (!done) {
230
+ session.waitingTimer = new timing_1.Timer('session_wait');
231
+ }
232
+ return {
233
+ ...result,
234
+ session_id: session.sessionId,
235
+ timing_info: timingInfo,
236
+ };
204
237
  }
205
238
  findCompileQuerySession(sessionId, sessionInfo) {
206
239
  const session = this.findSession(sessionId, sessionInfo);
@@ -220,6 +253,10 @@ class SessionManager {
220
253
  this.findCompileQuerySession(options.session_id, sessionInfo);
221
254
  this.purgeExpired({ except: options === null || options === void 0 ? void 0 : options.session_id });
222
255
  if (session) {
256
+ if (session.waitingTimer) {
257
+ session.timer.contribute([session.waitingTimer.stop()]);
258
+ session.waitingTimer = undefined;
259
+ }
223
260
  if (options === null || options === void 0 ? void 0 : options.ttl) {
224
261
  session.expires = this.getExpires(options.ttl);
225
262
  }
@@ -230,10 +267,20 @@ class SessionManager {
230
267
  this.sessions.set(session.sessionId, session);
231
268
  }
232
269
  const result = Core.statedCompileQuery(session.state);
233
- if (result.result || this.hasErrors(result.logs)) {
270
+ session.timer.incorporate(result.timing_info);
271
+ const done = result.result || this.hasErrors(result.logs);
272
+ if (done) {
234
273
  this.killSession(session.sessionId);
235
274
  }
236
- return { ...result, session_id: session.sessionId };
275
+ const timingInfo = session.timer.stop();
276
+ if (!done) {
277
+ session.waitingTimer = new timing_1.Timer('session_wait');
278
+ }
279
+ return {
280
+ ...result,
281
+ session_id: session.sessionId,
282
+ timing_info: timingInfo,
283
+ };
237
284
  }
238
285
  }
239
286
  const SESSION_MANAGER = new SessionManager();