@malloydata/malloy 0.0.296 → 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();
@@ -15,7 +15,7 @@ const util_1 = require("../functions/util");
15
15
  * So in this file we are experimenting with various ways to define things.
16
16
  * The most general and powerful is to write a DefinitionBlueprint or
17
17
  * OverloadedDefinitionBlueprint, naming it with the name of the function
18
- * you want to add, and then to add that name to the dialcect function list.
18
+ * you want to add, and then to add that name to the dialect function list.
19
19
  *
20
20
  * Experimentally, there is also a function def which creates a
21
21
  * DefinitionBlueprint for you. For simple blueprints, you can use the wrapper
@@ -235,7 +235,7 @@ const hll_accumulate_moving = {
235
235
  'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'],
236
236
  },
237
237
  impl: {
238
- function: 'APPROX_SET',
238
+ sql: 'APPROX_SET(${value}, 0.0040625)',
239
239
  needsWindowOrderBy: true,
240
240
  between: { preceding: 'preceding', following: 0 },
241
241
  },
@@ -251,7 +251,7 @@ const hll_accumulate_moving = {
251
251
  'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'],
252
252
  },
253
253
  impl: {
254
- function: 'APPROX_SET',
254
+ sql: 'APPROX_SET(${value}, 0.0040625)',
255
255
  needsWindowOrderBy: true,
256
256
  between: { preceding: 'preceding', following: 'following' },
257
257
  },
@@ -265,7 +265,7 @@ const hll_combine_moving = {
265
265
  },
266
266
  returns: { calculation: { sql_native: 'hyperloglog' } },
267
267
  impl: {
268
- function: 'MERGE',
268
+ sql: 'MERGE(${value})',
269
269
  needsWindowOrderBy: true,
270
270
  between: { preceding: 'preceding', following: 0 },
271
271
  },
@@ -284,32 +284,100 @@ const hll_combine_moving = {
284
284
  },
285
285
  },
286
286
  };
287
- const hll_estimate_moving = {
288
- preceding: {
289
- takes: {
290
- 'value': { sql_native: 'hyperloglog' },
291
- 'preceding': { literal: 'number' },
292
- },
293
- returns: { calculation: 'number' },
294
- impl: {
295
- function: 'CARDINALITY',
296
- needsWindowOrderBy: true,
297
- between: { preceding: 'preceding', following: 0 },
298
- },
287
+ // T-Digest functions for approximate quantile analytics
288
+ const tdigest_agg = {
289
+ default: {
290
+ takes: { 'value': { dimension: 'number' } },
291
+ returns: { measure: { sql_native: 'tdigest' } },
292
+ impl: { function: 'TDIGEST_AGG' },
293
+ isSymmetric: true,
299
294
  },
300
- following: {
295
+ with_weight: {
296
+ takes: { 'value': { dimension: 'number' }, 'weight': { dimension: 'number' } },
297
+ returns: { measure: { sql_native: 'tdigest' } },
298
+ impl: { function: 'TDIGEST_AGG' },
299
+ isSymmetric: true,
300
+ },
301
+ with_weight_and_compression: {
301
302
  takes: {
302
- 'value': { sql_native: 'hyperloglog' },
303
- 'preceding': { literal: 'number' },
304
- 'following': { literal: 'number' },
305
- },
306
- returns: { calculation: 'number' },
307
- impl: {
308
- function: 'CARDINALITY',
309
- needsWindowOrderBy: true,
310
- between: { preceding: 'preceding', following: 'following' },
303
+ 'value': { dimension: 'number' },
304
+ 'weight': { dimension: 'number' },
305
+ 'compression': { literal: 'number' },
311
306
  },
307
+ returns: { measure: { sql_native: 'tdigest' } },
308
+ impl: { function: 'TDIGEST_AGG' },
309
+ isSymmetric: true,
310
+ },
311
+ };
312
+ const merge_tdigest = {
313
+ takes: { 'tdigest_val': { sql_native: 'tdigest' } },
314
+ returns: { measure: { sql_native: 'tdigest' } },
315
+ impl: { function: 'MERGE' },
316
+ isSymmetric: true,
317
+ };
318
+ const value_at_quantile = {
319
+ takes: { 'tdigest_val': { sql_native: 'tdigest' }, 'quantile': 'number' },
320
+ returns: 'number',
321
+ impl: { function: 'VALUE_AT_QUANTILE' },
322
+ };
323
+ const quantile_at_value = {
324
+ takes: { 'tdigest_val': { sql_native: 'tdigest' }, 'value': 'number' },
325
+ returns: 'number',
326
+ impl: { function: 'QUANTILE_AT_VALUE' },
327
+ };
328
+ const scale_tdigest = {
329
+ takes: { 'tdigest_val': { sql_native: 'tdigest' }, 'scale_factor': 'number' },
330
+ returns: { sql_native: 'tdigest' },
331
+ impl: { function: 'SCALE_TDIGEST' },
332
+ };
333
+ const values_at_quantiles = {
334
+ takes: {
335
+ 'tdigest_val': { sql_native: 'tdigest' },
336
+ 'quantiles': { array: 'number' },
312
337
  },
338
+ returns: { array: 'number' },
339
+ impl: { function: 'VALUES_AT_QUANTILES' },
340
+ };
341
+ const trimmed_mean = {
342
+ takes: {
343
+ 'tdigest_val': { sql_native: 'tdigest' },
344
+ 'lower_quantile': 'number',
345
+ 'upper_quantile': 'number',
346
+ },
347
+ returns: 'number',
348
+ impl: { function: 'TRIMMED_MEAN' },
349
+ };
350
+ const destructure_tdigest = {
351
+ takes: { 'tdigest_val': { sql_native: 'tdigest' } },
352
+ returns: {
353
+ record: {
354
+ 'centroid_means': { array: 'number' },
355
+ 'centroid_weights': { array: 'number' },
356
+ 'min_value': 'number',
357
+ 'max_value': 'number',
358
+ 'sum_value': 'number',
359
+ 'count_value': 'number',
360
+ },
361
+ },
362
+ impl: { function: 'DESTRUCTURE_TDIGEST' },
363
+ };
364
+ const construct_tdigest = {
365
+ takes: {
366
+ 'centroid_means': { array: 'number' },
367
+ 'centroid_weights': { array: 'number' },
368
+ 'min_value': 'number',
369
+ 'max_value': 'number',
370
+ 'sum_value': 'number',
371
+ 'count_value': 'number',
372
+ 'compression': 'number',
373
+ },
374
+ returns: { sql_native: 'tdigest' },
375
+ impl: { function: 'CONSTRUCT_TDIGEST' },
376
+ };
377
+ const merge_tdigest_array = {
378
+ takes: { 'tdigest_array': { array: { sql_native: 'tdigest' } } },
379
+ returns: { sql_native: 'tdigest' },
380
+ impl: { function: 'MERGE_TDIGEST' },
313
381
  };
314
382
  /**
315
383
  * This map is for functions which exist in both Presto and Trino.
@@ -388,9 +456,6 @@ exports.TRINO_DIALECT_FUNCTIONS = {
388
456
  returns: { dimension: { sql_native: 'hyperloglog' } },
389
457
  impl: { sql: 'CAST(${value} AS HyperLogLog)' },
390
458
  },
391
- hll_accumulate_moving,
392
- hll_combine_moving,
393
- hll_estimate_moving,
394
459
  ...(0, util_1.def)('variance', { 'n': 'number' }, { measure: 'number' }),
395
460
  // scalar functions
396
461
  ...(0, util_1.def)('bitwise_and', { 'val1': 'number', 'val2': 'number' }, 'number'),
@@ -507,38 +572,18 @@ exports.PRESTO_DIALECT_FUNCTIONS = {
507
572
  impl: { sql: 'APPROX_SET(${value}, 0.0040625)' },
508
573
  },
509
574
  },
510
- hll_accumulate_moving: {
511
- preceding: {
512
- takes: {
513
- 'value': { dimension: T },
514
- 'preceding': { literal: 'number' },
515
- },
516
- returns: { calculation: { sql_native: 'hyperloglog' } },
517
- generic: {
518
- 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'],
519
- },
520
- impl: {
521
- sql: 'APPROX_SET(${value}, 0.0040625)',
522
- needsWindowOrderBy: true,
523
- between: { preceding: 'preceding', following: 0 },
524
- },
525
- },
526
- following: {
527
- takes: {
528
- 'value': { dimension: T },
529
- 'preceding': { literal: 'number' },
530
- 'following': { literal: 'number' },
531
- },
532
- returns: { calculation: { sql_native: 'hyperloglog' } },
533
- generic: {
534
- 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'],
535
- },
536
- impl: {
537
- sql: 'APPROX_SET(${value}, 0.0040625)',
538
- needsWindowOrderBy: true,
539
- between: { preceding: 'preceding', following: 'following' },
540
- },
541
- },
542
- },
575
+ hll_accumulate_moving,
576
+ hll_combine_moving,
577
+ // T-Digest functions
578
+ tdigest_agg,
579
+ merge_tdigest,
580
+ value_at_quantile,
581
+ quantile_at_value,
582
+ scale_tdigest,
583
+ values_at_quantiles,
584
+ trimmed_mean,
585
+ destructure_tdigest,
586
+ construct_tdigest,
587
+ merge_tdigest_array,
543
588
  };
544
589
  //# sourceMappingURL=dialect_functions.js.map
@@ -11,6 +11,8 @@ import type { HasString, HasID } from './parse-utils';
11
11
  import type { CastType } from '../model';
12
12
  import type { AccessModifierLabel, DocumentLocation, DocumentRange, Note } from '../model/malloy_types';
13
13
  import { Tag } from '@malloydata/malloy-tag';
14
+ import type * as Malloy from '@malloydata/malloy-interfaces';
15
+ import { Timer } from '../timing';
14
16
  declare class ErrorNode extends ast.SourceQueryElement {
15
17
  elementType: string;
16
18
  }
@@ -30,7 +32,13 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
30
32
  readonly parseInfo: MalloyParseInfo;
31
33
  readonly msgLog: MessageLogger;
32
34
  compilerFlags: Tag;
35
+ readonly timer: Timer;
33
36
  constructor(parseInfo: MalloyParseInfo, msgLog: MessageLogger, compilerFlags: Tag);
37
+ run(): {
38
+ ast: ast.MalloyElement;
39
+ compilerFlags: Tag;
40
+ timingInfo: Malloy.TimingInfo;
41
+ };
34
42
  /**
35
43
  * Mostly used to flag a case where the grammar and the type system are
36
44
  * no longer in sync. A visitor was written based on a grammar which
@@ -205,6 +213,7 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
205
213
  visitImportStatement(pcx: parse.ImportStatementContext): ast.ImportStatement;
206
214
  visitDebugExpr(pcx: parse.DebugExprContext): ast.ExpressionDef;
207
215
  visitSampleStatement(pcx: parse.SampleStatementContext): ast.SampleProperty;
216
+ updateCompilerFlags(tags: ast.ModelAnnotation): void;
208
217
  visitDocAnnotations(pcx: parse.DocAnnotationsContext): ast.ModelAnnotation;
209
218
  visitIgnoredObjectAnnotations(pcx: parse.IgnoredObjectAnnotationsContext): IgnoredElement;
210
219
  visitIgnoredModelAnnotations(pcx: parse.IgnoredModelAnnotationsContext): IgnoredElement;
@@ -68,6 +68,7 @@ const malloy_types_1 = require("../model/malloy_types");
68
68
  const malloy_tag_1 = require("@malloydata/malloy-tag");
69
69
  const utils_1 = require("./utils");
70
70
  const malloy_filter_1 = require("@malloydata/malloy-filter");
71
+ const timing_1 = require("../timing");
71
72
  class ErrorNode extends ast.SourceQueryElement {
72
73
  constructor() {
73
74
  super(...arguments);
@@ -92,10 +93,22 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
92
93
  this.parseInfo = parseInfo;
93
94
  this.msgLog = msgLog;
94
95
  this.compilerFlags = compilerFlags;
96
+ this.timer = new timing_1.Timer('generate_ast');
97
+ const parseCompilerFlagsTimer = new timing_1.Timer('parse_compiler_flags');
95
98
  for (const flag of DEFAULT_COMPILER_FLAGS) {
96
99
  const withNewTag = malloy_tag_1.Tag.fromTagLine(flag, 0, this.compilerFlags);
97
100
  this.compilerFlags = withNewTag.tag;
98
101
  }
102
+ this.timer.contribute([parseCompilerFlagsTimer.stop()]);
103
+ }
104
+ run() {
105
+ const ast = this.visit(this.parseInfo.root);
106
+ const compilerFlags = this.compilerFlags;
107
+ return {
108
+ ast,
109
+ compilerFlags,
110
+ timingInfo: this.timer.stop(),
111
+ };
99
112
  }
100
113
  /**
101
114
  * Mostly used to flag a case where the grammar and the type system are
@@ -1254,6 +1267,11 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1254
1267
  const enabled = pcx.sampleSpec().TRUE() !== undefined;
1255
1268
  return new ast.SampleProperty({ enable: enabled });
1256
1269
  }
1270
+ updateCompilerFlags(tags) {
1271
+ const parseCompilerFlagsTimer = new timing_1.Timer('parse_compiler_flags');
1272
+ this.compilerFlags = tags.getCompilerFlags(this.compilerFlags, this.msgLog);
1273
+ this.timer.contribute([parseCompilerFlagsTimer.stop()]);
1274
+ }
1257
1275
  visitDocAnnotations(pcx) {
1258
1276
  const allNotes = pcx.DOC_ANNOTATION().map(note => {
1259
1277
  return {
@@ -1262,7 +1280,7 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1262
1280
  };
1263
1281
  });
1264
1282
  const tags = new ast.ModelAnnotation(allNotes);
1265
- this.compilerFlags = tags.getCompilerFlags(this.compilerFlags, this.msgLog);
1283
+ this.updateCompilerFlags(tags);
1266
1284
  return tags;
1267
1285
  }
1268
1286
  visitIgnoredObjectAnnotations(pcx) {
@@ -4,7 +4,7 @@ import { BaseMessageLogger } from './parse-log';
4
4
  import type { ZoneData } from './zone';
5
5
  import { Zone } from './zone';
6
6
  import { ReferenceList } from './reference-list';
7
- import type { ASTResponse, CompletionsResponse, DataRequestResponse, ProblemResponse, FatalResponse, FinalResponse, HelpContextResponse, MetadataResponse, ModelDataRequest, NeedURLData, TranslateResponse, ModelAnnotationResponse, TablePathResponse } from './translate-response';
7
+ import type { ResponseBase, ASTResponse, CompletionsResponse, DataRequestResponse, ProblemResponse, FatalResponse, FinalResponse, HelpContextResponse, MetadataResponse, ModelDataRequest, NeedURLData, TranslateResponse, ModelAnnotationResponse, TablePathResponse } from './translate-response';
8
8
  import { Tag } from '@malloydata/malloy-tag';
9
9
  import type { MalloyParseInfo } from './malloy-parse-info';
10
10
  import type { EventStream } from '../runtime_types';
@@ -25,7 +25,7 @@ export type StepResponses = DataRequestResponse | ASTResponse | TranslateRespons
25
25
  interface TranslationStep {
26
26
  step(that: MalloyTranslation): StepResponses;
27
27
  }
28
- interface ParseData extends ProblemResponse, NeedURLData, FinalResponse {
28
+ interface ParseData extends ResponseBase, ProblemResponse, NeedURLData, FinalResponse {
29
29
  parse: MalloyParseInfo;
30
30
  }
31
31
  export type ParseResponse = Partial<ParseData>;
@@ -73,8 +73,10 @@ const model_annotation_walker_1 = require("./parse-tree-walkers/model-annotation
73
73
  const find_table_path_walker_1 = require("./parse-tree-walkers/find-table-path-walker");
74
74
  const annotation_1 = require("../annotation");
75
75
  const run_malloy_parser_1 = require("./run-malloy-parser");
76
+ const timing_1 = require("../timing");
76
77
  class ParseStep {
77
78
  step(that) {
79
+ const stepTimer = new timing_1.Timer('parse_step');
78
80
  if (this.response) {
79
81
  return this.response;
80
82
  }
@@ -94,6 +96,7 @@ class ParseStep {
94
96
  }
95
97
  return { urls: [that.sourceURL] };
96
98
  }
99
+ const parseModelTimer = new timing_1.Timer('parse_malloy');
97
100
  const source = srcEnt.value === '' ? '\n' : srcEnt.value;
98
101
  this.sourceInfo = (0, utils_1.getSourceInfo)(source);
99
102
  let parse;
@@ -104,6 +107,7 @@ class ParseStep {
104
107
  that.root.logError('parse-exception', { message: parseException.message });
105
108
  parse = undefined;
106
109
  }
110
+ stepTimer.contribute([parseModelTimer.stop()]);
107
111
  if (that.root.logger.hasErrors()) {
108
112
  this.response = {
109
113
  parse,
@@ -113,7 +117,7 @@ class ParseStep {
113
117
  else {
114
118
  this.response = { parse };
115
119
  }
116
- return this.response;
120
+ return { ...this.response, timingInfo: stepTimer.stop() };
117
121
  }
118
122
  runParser(source, sourceInfo, that) {
119
123
  const parse = (0, run_malloy_parser_1.runMalloyParser)(source, that.sourceURL, sourceInfo, that.root.logger, that.grammarRule);
@@ -167,7 +171,7 @@ class ImportsAndTablesStep {
167
171
  if (that.root.logger.hasErrors()) {
168
172
  // Since we knew we parsed without errors, this would only be from
169
173
  // having a malformed URL on an import reference.
170
- return null;
174
+ return { timingInfo: parseReq.timingInfo };
171
175
  }
172
176
  let allMissing = {};
173
177
  const missingTables = that.root.schemaZone.getUndefined();
@@ -184,10 +188,13 @@ class ImportsAndTablesStep {
184
188
  }
185
189
  const missingImports = ((_a = that.root.importZone.getUndefined()) !== null && _a !== void 0 ? _a : []).filter(url => that.root.pretranslatedModels.get(url) === undefined);
186
190
  if (missingImports.length > 0) {
187
- allMissing = { ...allMissing, urls: missingImports };
191
+ allMissing = {
192
+ ...allMissing,
193
+ urls: missingImports,
194
+ };
188
195
  }
189
196
  if ((0, translate_response_1.isNeedResponse)(allMissing)) {
190
- return allMissing;
197
+ return { ...allMissing, timingInfo: parseReq.timingInfo };
191
198
  }
192
199
  for (const child of that.childTranslators.values()) {
193
200
  if (that.root.pretranslatedModels.get(child.sourceURL)) {
@@ -198,7 +205,7 @@ class ImportsAndTablesStep {
198
205
  return kidNeeds;
199
206
  }
200
207
  }
201
- return null;
208
+ return { timingInfo: parseReq.timingInfo };
202
209
  }
203
210
  }
204
211
  class ASTStep {
@@ -207,11 +214,13 @@ class ASTStep {
207
214
  this.walked = false;
208
215
  }
209
216
  step(that) {
217
+ const stepTimer = new timing_1.Timer('ast_step');
210
218
  if (this.response) {
211
219
  return this.response;
212
220
  }
213
221
  const mustResolve = this.importStep.step(that);
214
- if (mustResolve) {
222
+ stepTimer.incorporate(mustResolve === null || mustResolve === void 0 ? void 0 : mustResolve.timingInfo);
223
+ if ((0, translate_response_1.isNeedResponse)(mustResolve)) {
215
224
  return mustResolve;
216
225
  }
217
226
  const parseResponse = that.parseStep.response;
@@ -224,17 +233,19 @@ class ASTStep {
224
233
  if (!parse) {
225
234
  throw new Error('TRANSLATOR INTERNAL ERROR: Translator parse response had no errors, but also no parser');
226
235
  }
236
+ stepTimer.incorporate(parseResponse.timingInfo);
227
237
  const secondPass = new malloy_to_ast_1.MalloyToAST(parse, that.root.logger, that.compilerFlags);
228
- const newAst = secondPass.visit(parse.root);
229
- that.compilerFlags = secondPass.compilerFlags;
230
- if (newAst.elementType === 'unimplemented') {
231
- newAst.logError('untranslated-parse-node', 'INTERNAL COMPILER ERROR: Untranslated parse node');
238
+ const { ast: newAST, compilerFlags, timingInfo } = secondPass.run();
239
+ stepTimer.contribute([timingInfo]);
240
+ that.compilerFlags = compilerFlags;
241
+ if (newAST.elementType === 'unimplemented') {
242
+ newAST.logError('untranslated-parse-node', 'INTERNAL COMPILER ERROR: Untranslated parse node');
232
243
  }
233
244
  if (!this.walked) {
234
245
  // The DocumentStatement.needs method has largely replaced the need to walk
235
246
  // the AST once it has been translated, this one check remains, though
236
247
  // it should probably never be hit
237
- for (const walkedTo of newAst.walk()) {
248
+ for (const walkedTo of newAST.walk()) {
238
249
  if (walkedTo instanceof ast.Unimplemented) {
239
250
  walkedTo.logError('untranslated-parse-node', 'INTERNAL COMPILER ERROR: Untranslated parse node');
240
251
  }
@@ -256,13 +267,13 @@ class ASTStep {
256
267
  return kidNeeds;
257
268
  }
258
269
  }
259
- newAst.setTranslator(that);
270
+ newAST.setTranslator(that);
260
271
  this.response = {
261
272
  ...that.problemResponse(), // these problems will by definition all be warnings
262
- ast: newAst,
273
+ ast: newAST,
263
274
  final: true,
264
275
  };
265
- return this.response;
276
+ return { ...this.response, timingInfo: stepTimer.stop() };
266
277
  }
267
278
  }
268
279
  class MetadataStep {
@@ -397,6 +408,7 @@ class TranslateStep {
397
408
  this.importedAnnotations = false;
398
409
  }
399
410
  step(that, extendingModel) {
411
+ const stepTimer = new timing_1.Timer('translate_step');
400
412
  if (this.response) {
401
413
  return this.response;
402
414
  }
@@ -411,13 +423,16 @@ class TranslateStep {
411
423
  }
412
424
  // begin with the compiler flags of the model we are extending
413
425
  if (extendingModel && !this.importedAnnotations) {
426
+ const parseCompilerFlagsTimer = new timing_1.Timer('parse_compiler_flags');
414
427
  const tagParse = (0, annotation_1.annotationToTag)(extendingModel.annotation, {
415
428
  prefix: /^##! /,
416
429
  });
430
+ stepTimer.contribute([parseCompilerFlagsTimer.stop()]);
417
431
  that.compilerFlags = tagParse.tag;
418
432
  this.importedAnnotations = true;
419
433
  }
420
434
  const astResponse = this.astStep.step(that);
435
+ stepTimer.incorporate(astResponse.timingInfo);
421
436
  if ((0, translate_response_1.isNeedResponse)(astResponse)) {
422
437
  return astResponse;
423
438
  }
@@ -429,15 +444,18 @@ class TranslateStep {
429
444
  if (astResponse.ast instanceof ast.Document) {
430
445
  const doc = astResponse.ast;
431
446
  doc.initModelDef(extendingModel);
432
- for (;;) {
433
- const docCompile = doc.compile();
434
- if (docCompile.needs) {
435
- return docCompile.needs;
436
- }
437
- else {
438
- that.modelDef = docCompile.modelDef;
439
- break;
440
- }
447
+ const translateModelTimer = new timing_1.Timer('compile_malloy');
448
+ const docCompile = doc.compile();
449
+ const translateTiming = translateModelTimer.stop();
450
+ stepTimer.contribute([translateTiming]);
451
+ if (docCompile.needs) {
452
+ return {
453
+ ...docCompile.needs,
454
+ timingInfo: stepTimer.stop(),
455
+ };
456
+ }
457
+ else {
458
+ that.modelDef = docCompile.modelDef;
441
459
  }
442
460
  }
443
461
  else {
@@ -463,7 +481,7 @@ class TranslateStep {
463
481
  final: true,
464
482
  };
465
483
  }
466
- return this.response;
484
+ return { ...this.response, timingInfo: stepTimer.stop() };
467
485
  }
468
486
  }
469
487
  class MalloyTranslation {
@@ -1,3 +1,4 @@
1
+ import type * as Malloy from '@malloydata/malloy-interfaces';
1
2
  import type { Annotation, ModelDef } from '../model/malloy_types';
2
3
  import type { MalloyElement } from './ast';
3
4
  import type { LogMessage } from './parse-log';
@@ -5,6 +6,9 @@ import type { DocumentSymbol } from './parse-tree-walkers/document-symbol-walker
5
6
  import type { DocumentCompletion } from './parse-tree-walkers/document-completion-walker';
6
7
  import type { DocumentHelpContext } from './parse-tree-walkers/document-help-context-walker';
7
8
  import type { PathInfo } from './parse-tree-walkers/find-table-path-walker';
9
+ export interface ResponseBase {
10
+ timingInfo?: Malloy.TimingInfo;
11
+ }
8
12
  /**
9
13
  * The translation interface is essentially a request/response protocol, and
10
14
  * this is the list of all the "protocol" messages.
@@ -34,34 +38,34 @@ export interface NeedCompileSQL {
34
38
  }
35
39
  interface NeededData extends NeedURLData, NeedSchemaData, NeedCompileSQL {
36
40
  }
37
- export type DataRequestResponse = Partial<NeededData> | null;
41
+ export type DataRequestResponse = Partial<NeededData> & ResponseBase;
38
42
  export declare function isNeedResponse(dr: DataRequestResponse): dr is NeededData;
39
43
  export type ModelDataRequest = NeedCompileSQL | undefined;
40
- interface ASTData extends ProblemResponse, NeededData, FinalResponse {
44
+ interface ASTData extends ResponseBase, ProblemResponse, NeededData, FinalResponse {
41
45
  ast: MalloyElement;
42
46
  }
43
47
  export type ASTResponse = Partial<ASTData>;
44
- interface Metadata extends NeededData, ProblemResponse, FinalResponse {
48
+ interface Metadata extends ResponseBase, NeededData, ProblemResponse, FinalResponse {
45
49
  symbols: DocumentSymbol[];
46
50
  }
47
51
  export type MetadataResponse = Partial<Metadata>;
48
- interface ModelAnnotationData extends NeededData, ProblemResponse, FinalResponse {
52
+ interface ModelAnnotationData extends ResponseBase, NeededData, ProblemResponse, FinalResponse {
49
53
  modelAnnotation: Annotation;
50
54
  }
51
55
  export type ModelAnnotationResponse = Partial<ModelAnnotationData>;
52
- interface Completions extends NeededData, ProblemResponse, FinalResponse {
56
+ interface Completions extends ResponseBase, NeededData, ProblemResponse, FinalResponse {
53
57
  completions: DocumentCompletion[];
54
58
  }
55
59
  export type CompletionsResponse = Partial<Completions>;
56
- interface HelpContext extends NeededData, ProblemResponse, FinalResponse {
60
+ interface HelpContext extends ResponseBase, NeededData, ProblemResponse, FinalResponse {
57
61
  helpContext: DocumentHelpContext | undefined;
58
62
  }
59
63
  export type HelpContextResponse = Partial<HelpContext>;
60
- interface TranslatedResponseData extends NeededData, ProblemResponse, FinalResponse {
64
+ interface TranslatedResponseData extends ResponseBase, NeededData, ProblemResponse, FinalResponse {
61
65
  modelDef: ModelDef;
62
66
  fromSources: string[];
63
67
  }
64
- interface TablePath extends NeededData, ProblemResponse, FinalResponse {
68
+ interface TablePath extends ResponseBase, NeededData, ProblemResponse, FinalResponse {
65
69
  pathInfo: PathInfo[];
66
70
  }
67
71
  export type TablePathResponse = Partial<TablePath>;
@@ -0,0 +1,11 @@
1
+ import type * as Malloy from '@malloydata/malloy-interfaces';
2
+ export declare class Timer {
3
+ readonly name: string;
4
+ readonly startTime: number;
5
+ private endTime;
6
+ private detailedTiming;
7
+ constructor(name: string);
8
+ incorporate(timing: Malloy.TimingInfo | undefined): void;
9
+ contribute(timings: Malloy.TimingInfo[] | undefined): void;
10
+ stop(): Malloy.TimingInfo;
11
+ }
package/dist/timing.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.Timer = void 0;
10
+ class Timer {
11
+ constructor(name) {
12
+ this.name = name;
13
+ this.endTime = undefined;
14
+ this.detailedTiming = [];
15
+ this.startTime = performance.now();
16
+ }
17
+ incorporate(timing) {
18
+ this.contribute(timing === null || timing === void 0 ? void 0 : timing.detailed_timing);
19
+ }
20
+ contribute(timings) {
21
+ this.detailedTiming.push(...(timings !== null && timings !== void 0 ? timings : []));
22
+ }
23
+ stop() {
24
+ this.endTime = performance.now();
25
+ return {
26
+ name: this.name,
27
+ duration_ms: this.endTime - this.startTime,
28
+ detailed_timing: [...this.detailedTiming.values()],
29
+ };
30
+ }
31
+ }
32
+ exports.Timer = Timer;
33
+ //# sourceMappingURL=timing.js.map
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const MALLOY_VERSION = "0.0.296";
1
+ export declare const MALLOY_VERSION = "0.0.297";
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MALLOY_VERSION = void 0;
4
4
  // generated with 'generate-version-file' script; do not edit manually
5
- exports.MALLOY_VERSION = '0.0.296';
5
+ exports.MALLOY_VERSION = '0.0.297';
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.296",
3
+ "version": "0.0.297",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -41,9 +41,9 @@
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-filter": "0.0.296",
45
- "@malloydata/malloy-interfaces": "0.0.296",
46
- "@malloydata/malloy-tag": "0.0.296",
44
+ "@malloydata/malloy-filter": "0.0.297",
45
+ "@malloydata/malloy-interfaces": "0.0.297",
46
+ "@malloydata/malloy-tag": "0.0.297",
47
47
  "antlr4ts": "^0.5.0-alpha.4",
48
48
  "assert": "^2.0.0",
49
49
  "jaro-winkler": "^0.2.8",