@malloydata/malloy 0.0.240-dev250311155207 → 0.0.240-dev250311213218

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 (37) hide show
  1. package/dist/api/asynchronous.js +4 -4
  2. package/dist/api/asynchronous.spec.js +8 -6
  3. package/dist/api/connection.d.ts +1 -1
  4. package/dist/api/core.d.ts +2 -0
  5. package/dist/api/core.js +29 -1
  6. package/dist/api/index.d.ts +2 -0
  7. package/dist/api/index.js +6 -1
  8. package/dist/api/sessioned.js +1 -2
  9. package/dist/api/sessioned.spec.js +1 -1
  10. package/dist/api/stateless.spec.js +7 -1
  11. package/dist/api/util.d.ts +9 -0
  12. package/dist/api/util.js +215 -0
  13. package/dist/index.d.ts +1 -1
  14. package/dist/lang/malloy-parse-info.d.ts +2 -10
  15. package/dist/lang/malloy-to-ast.d.ts +1 -0
  16. package/dist/lang/malloy-to-ast.js +9 -6
  17. package/dist/lang/malloy-to-stable-query.d.ts +76 -0
  18. package/dist/lang/malloy-to-stable-query.js +660 -0
  19. package/dist/lang/parse-log.d.ts +1 -0
  20. package/dist/lang/parse-malloy.d.ts +2 -9
  21. package/dist/lang/parse-malloy.js +7 -112
  22. package/dist/lang/parse-tree-walkers/model-annotation-walker.js +1 -1
  23. package/dist/lang/run-malloy-parser.d.ts +3 -0
  24. package/dist/lang/run-malloy-parser.js +53 -0
  25. package/dist/lang/syntax-errors/malloy-parser-error-listener.d.ts +4 -3
  26. package/dist/lang/syntax-errors/malloy-parser-error-listener.js +8 -4
  27. package/dist/lang/test/malloy-to-stable-query.spec.d.ts +1 -0
  28. package/dist/lang/test/malloy-to-stable-query.spec.js +365 -0
  29. package/dist/lang/utils.d.ts +27 -1
  30. package/dist/lang/utils.js +78 -1
  31. package/dist/malloy.d.ts +1 -1
  32. package/dist/malloy.js +1 -5
  33. package/dist/model/malloy_query.d.ts +1 -0
  34. package/dist/model/malloy_query.js +6 -2
  35. package/dist/to_stable.d.ts +2 -1
  36. package/dist/to_stable.js +34 -3
  37. package/package.json +3 -3
@@ -121,7 +121,7 @@ async function compileModel(request, fetchers) {
121
121
  // eslint-disable-next-line no-constant-condition
122
122
  while (true) {
123
123
  const result = Core.statedCompileModel(state);
124
- if (result.model) {
124
+ if (result.model || Core.hasErrors(result.logs)) {
125
125
  return result;
126
126
  }
127
127
  const needs = await fetchNeeds(result.compiler_needs, fetchers);
@@ -134,7 +134,7 @@ async function compileSource(request, fetchers) {
134
134
  // eslint-disable-next-line no-constant-condition
135
135
  while (true) {
136
136
  const result = Core.statedCompileSource(state, request.name);
137
- if (result.source) {
137
+ if (result.source || Core.hasErrors(result.logs)) {
138
138
  return result;
139
139
  }
140
140
  const needs = await fetchNeeds(result.compiler_needs, fetchers);
@@ -147,7 +147,7 @@ async function compileQuery(request, fetchers) {
147
147
  // eslint-disable-next-line no-constant-condition
148
148
  while (true) {
149
149
  const result = Core.statedCompileQuery(state);
150
- if (result.result) {
150
+ if (result.result || Core.hasErrors(result.logs)) {
151
151
  return result;
152
152
  }
153
153
  const needs = await fetchNeeds(result.compiler_needs, fetchers);
@@ -177,7 +177,7 @@ async function runQuery(request, fetchers) {
177
177
  }
178
178
  try {
179
179
  const connection = await fetchers.connections.lookupConnection(compiled.result.connection_name);
180
- const data = await connection.runSQL(compiled.result.sql);
180
+ const data = await connection.runSQL(compiled.result.sql, compiled.result.schema);
181
181
  return {
182
182
  ...compiled,
183
183
  result: {
@@ -105,7 +105,7 @@ describe('api', () => {
105
105
  query: {
106
106
  definition: {
107
107
  kind: 'arrow',
108
- source_reference: { name: 'flights' },
108
+ source: { kind: 'source_reference', name: 'flights' },
109
109
  view: {
110
110
  kind: 'segment',
111
111
  operations: [
@@ -146,13 +146,15 @@ ORDER BY 1 asc NULLS LAST
146
146
  describe('run query', () => {
147
147
  test('run query with table dependency', async () => {
148
148
  const data = {
149
- kind: 'table',
150
- rows: [
149
+ kind: 'array_cell',
150
+ array_value: [
151
151
  {
152
- cells: [{ kind: 'string_cell', string_value: 'WN' }],
152
+ kind: 'record_cell',
153
+ record_value: [{ kind: 'string_cell', string_value: 'WN' }],
153
154
  },
154
155
  {
155
- cells: [{ kind: 'string_cell', string_value: 'AA' }],
156
+ kind: 'record_cell',
157
+ record_value: [{ kind: 'string_cell', string_value: 'AA' }],
156
158
  },
157
159
  ],
158
160
  };
@@ -195,7 +197,7 @@ ORDER BY 1 asc NULLS LAST
195
197
  query: {
196
198
  definition: {
197
199
  kind: 'arrow',
198
- source_reference: { name: 'flights' },
200
+ source: { kind: 'source_reference', name: 'flights' },
199
201
  view: {
200
202
  kind: 'segment',
201
203
  operations: [
@@ -5,7 +5,7 @@ export interface InfoConnection {
5
5
  get dialectName(): string;
6
6
  }
7
7
  export interface Connection extends InfoConnection {
8
- runSQL(sql: string): Promise<Malloy.Data>;
8
+ runSQL(sql: string, schema: Malloy.Schema): Promise<Malloy.Data>;
9
9
  }
10
10
  export interface LookupConnection<T extends InfoConnection> {
11
11
  lookupConnection(connectionName?: string): Promise<T>;
@@ -31,7 +31,9 @@ export declare function statedCompileModel(state: CompileModelState): Malloy.Com
31
31
  export declare function statedCompileSource(state: CompileModelState, name: string): Malloy.CompileSourceResponse;
32
32
  export declare function _statedCompileModel(state: CompileModelState): CompileResponse;
33
33
  export declare const DEFAULT_LOG_RANGE: Malloy.DocumentRange;
34
+ export declare function mapLogs(logs: LogMessage[], defaultURL: string): Malloy.LogMessage[];
34
35
  export declare function compileModel(request: Malloy.CompileModelRequest, state?: CompileModelState): Malloy.CompileModelResponse;
35
36
  export declare function compileSource(request: Malloy.CompileSourceRequest): Malloy.CompileSourceResponse;
37
+ export declare function hasErrors(log: Malloy.LogMessage[] | undefined): boolean;
36
38
  export declare function newCompileQueryState(request: Malloy.CompileQueryRequest): CompileModelState;
37
39
  export declare function statedCompileQuery(state: CompileModelState): Malloy.CompileQueryResponse;
package/dist/api/core.js CHANGED
@@ -29,12 +29,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
29
29
  return result;
30
30
  };
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.statedCompileQuery = exports.newCompileQueryState = exports.compileSource = exports.compileModel = exports.DEFAULT_LOG_RANGE = exports._statedCompileModel = exports.statedCompileSource = exports.statedCompileModel = exports.newCompileSourceState = exports.newCompileModelState = exports.updateCompileModelState = exports.compileQuery = void 0;
32
+ exports.statedCompileQuery = exports.newCompileQueryState = exports.hasErrors = exports.compileSource = exports.compileModel = exports.mapLogs = exports.DEFAULT_LOG_RANGE = exports._statedCompileModel = exports.statedCompileSource = exports.statedCompileModel = exports.newCompileSourceState = exports.newCompileModelState = exports.updateCompileModelState = exports.compileQuery = void 0;
33
33
  const Malloy = __importStar(require("@malloydata/malloy-interfaces"));
34
34
  const lang_1 = require("../lang");
35
35
  const model_1 = require("../model");
36
36
  const to_stable_1 = require("../to_stable");
37
37
  const sql_block_1 = require("../model/sql_block");
38
+ const annotation_1 = require("../annotation");
39
+ const malloy_tag_1 = require("@malloydata/malloy-tag");
38
40
  // TODO find where this should go...
39
41
  function tableKey(connectionName, tablePath) {
40
42
  return `${connectionName}:${tablePath}`;
@@ -324,6 +326,7 @@ function mapLogs(logs, defaultURL) {
324
326
  });
325
327
  });
326
328
  }
329
+ exports.mapLogs = mapLogs;
327
330
  function wrapResponse(response, defaultURL) {
328
331
  const logs = response.logs ? mapLogs(response.logs, defaultURL) : undefined;
329
332
  if (response.compilerNeeds) {
@@ -371,6 +374,11 @@ function extractSource(result, name, defaultURL) {
371
374
  return { compiler_needs: result.compilerNeeds, logs };
372
375
  }
373
376
  }
377
+ function hasErrors(log) {
378
+ var _a;
379
+ return (_a = log === null || log === void 0 ? void 0 : log.some(m => m.severity === 'error')) !== null && _a !== void 0 ? _a : false;
380
+ }
381
+ exports.hasErrors = hasErrors;
374
382
  // Given a StableQueryDef and the URL to a model, run it and return a StableResult
375
383
  // Given a StableQueryDef and the URL to a model, compile it and return a StableResultDef
376
384
  // Given a StableQueryDef and the URL to a model, validate it and return a list of StableErrors
@@ -393,6 +401,7 @@ function newCompileQueryState(request) {
393
401
  }
394
402
  exports.newCompileQueryState = newCompileQueryState;
395
403
  function statedCompileQuery(state) {
404
+ var _a;
396
405
  const result = _statedCompileModel(state);
397
406
  // TODO this can expose the internal URL... is there a better way to handle URL-less errors from the compiler?
398
407
  const defaultURL = state.translator.sourceURL;
@@ -415,14 +424,33 @@ function statedCompileQuery(state) {
415
424
  const index = queries.length - 1;
416
425
  const query = result.modelDef.queryList[index];
417
426
  const schema = result.model.anonymous_queries[index].schema;
427
+ const annotations = (_a = result.model.anonymous_queries[index].annotations) !== null && _a !== void 0 ? _a : [];
418
428
  try {
419
429
  const queryModel = new model_1.QueryModel(result.modelDef);
420
430
  const translatedQuery = queryModel.compileQuery(query);
431
+ const modelAnnotations = (0, annotation_1.annotationToTaglines)(result.modelDef.annotation).map(l => ({
432
+ value: l,
433
+ }));
434
+ annotations.push({
435
+ value: malloy_tag_1.Tag.withPrefix('#(malloy) ')
436
+ .set(['source_name'], translatedQuery.sourceExplore)
437
+ .toString(),
438
+ });
439
+ if (translatedQuery.queryName) {
440
+ annotations.push({
441
+ value: malloy_tag_1.Tag.withPrefix('#(malloy) ')
442
+ .set(['query_name'], translatedQuery.queryName)
443
+ .toString(),
444
+ });
445
+ }
421
446
  return {
422
447
  result: {
423
448
  sql: translatedQuery.sql,
424
449
  schema,
425
450
  connection_name: translatedQuery.connectionName,
451
+ annotations: annotations.length > 0 ? annotations : undefined,
452
+ model_annotations: modelAnnotations.length > 0 ? modelAnnotations : undefined,
453
+ query_timezone: translatedQuery.queryTimezone,
426
454
  },
427
455
  };
428
456
  }
@@ -1,3 +1,5 @@
1
1
  export * as sessioned from './sessioned';
2
2
  export * as stateless from './stateless';
3
3
  export * as asynchronous from './asynchronous';
4
+ export * from './connection';
5
+ export * as util from './util';
package/dist/api/index.js CHANGED
@@ -22,8 +22,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
26
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.asynchronous = exports.stateless = exports.sessioned = void 0;
29
+ exports.util = exports.asynchronous = exports.stateless = exports.sessioned = void 0;
27
30
  /*
28
31
  * Copyright (c) Meta Platforms, Inc. and affiliates.
29
32
  *
@@ -33,4 +36,6 @@ exports.asynchronous = exports.stateless = exports.sessioned = void 0;
33
36
  exports.sessioned = __importStar(require("./sessioned"));
34
37
  exports.stateless = __importStar(require("./stateless"));
35
38
  exports.asynchronous = __importStar(require("./asynchronous"));
39
+ __exportStar(require("./connection"), exports);
40
+ exports.util = __importStar(require("./util"));
36
41
  //# sourceMappingURL=index.js.map
@@ -131,8 +131,7 @@ class SessionManager {
131
131
  this.sessions.delete(sessionId);
132
132
  }
133
133
  hasErrors(log) {
134
- var _a;
135
- return (_a = log === null || log === void 0 ? void 0 : log.some(m => m.severity === 'error')) !== null && _a !== void 0 ? _a : false;
134
+ return Core.hasErrors(log);
136
135
  }
137
136
  compileModel(request, options) {
138
137
  const sessionInfo = {
@@ -161,7 +161,7 @@ describe('api', () => {
161
161
  const query = {
162
162
  definition: {
163
163
  kind: 'arrow',
164
- source_reference: { name: 'flights' },
164
+ source: { kind: 'source_reference', name: 'flights' },
165
165
  view: {
166
166
  kind: 'segment',
167
167
  operations: [
@@ -269,9 +269,10 @@ describe('api', () => {
269
269
  const result = (0, stateless_1.compileQuery)({
270
270
  model_url: 'file://test.malloy',
271
271
  query: {
272
+ annotations: [{ value: '#(test) hello' }],
272
273
  definition: {
273
274
  kind: 'arrow',
274
- source_reference: { name: 'flights' },
275
+ source: { kind: 'source_reference', name: 'flights' },
275
276
  view: {
276
277
  kind: 'segment',
277
278
  operations: [
@@ -313,6 +314,11 @@ describe('api', () => {
313
314
  const expected = {
314
315
  result: {
315
316
  connection_name: 'connection',
317
+ annotations: [
318
+ { value: '#(test) hello\n' },
319
+ { value: '#(malloy) ordered_by = [{ carrier = asc }]\n' },
320
+ { value: '#(malloy) source_name = flights\n' },
321
+ ],
316
322
  sql: `SELECT \n\
317
323
  base."carrier" as "carrier"
318
324
  FROM flights as base
@@ -0,0 +1,9 @@
1
+ import { InfoConnection as LegacyInfoConnection, Connection as LegacyConnection } from '../connection';
2
+ import { Result } from '../malloy';
3
+ import { QueryData } from '../model';
4
+ import { Connection, InfoConnection } from './connection';
5
+ import * as Malloy from '@malloydata/malloy-interfaces';
6
+ export declare function wrapLegacyInfoConnection(connection: LegacyInfoConnection): InfoConnection;
7
+ export declare function wrapLegacyConnection(connection: LegacyConnection): Connection;
8
+ export declare function mapData(data: QueryData, schema: Malloy.Schema): Malloy.Data;
9
+ export declare function wrapResult(result: Result): Malloy.Result;
@@ -0,0 +1,215 @@
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.wrapResult = exports.mapData = exports.wrapLegacyConnection = exports.wrapLegacyInfoConnection = void 0;
10
+ const malloy_tag_1 = require("@malloydata/malloy-tag");
11
+ const annotation_1 = require("../annotation");
12
+ const to_stable_1 = require("../to_stable");
13
+ const luxon_1 = require("luxon");
14
+ function wrapLegacyInfoConnection(connection) {
15
+ return {
16
+ get dialectName() {
17
+ return connection.dialectName;
18
+ },
19
+ async fetchSchemaForSQLQuery(sql) {
20
+ const result = await connection.fetchSchemaForSQLStruct({ connection: connection.name, selectStr: sql }, {});
21
+ const table = result.structDef;
22
+ if (table === undefined) {
23
+ throw new Error(result.error);
24
+ }
25
+ return {
26
+ fields: (0, to_stable_1.convertFieldInfos)(table, table.fields),
27
+ };
28
+ },
29
+ async fetchSchemaForTable(tableName) {
30
+ const key = `${connection.name}:${tableName}`;
31
+ const result = await connection.fetchSchemaForTables({ [key]: tableName }, {});
32
+ const table = result.schemas[key];
33
+ if (table === undefined) {
34
+ throw new Error(result.errors[key]);
35
+ }
36
+ return {
37
+ fields: (0, to_stable_1.convertFieldInfos)(table, table.fields),
38
+ };
39
+ },
40
+ };
41
+ }
42
+ exports.wrapLegacyInfoConnection = wrapLegacyInfoConnection;
43
+ function wrapLegacyConnection(connection) {
44
+ return {
45
+ ...wrapLegacyInfoConnection(connection),
46
+ runSQL: async (sql, schema) => {
47
+ const result = await connection.runSQL(sql);
48
+ return mapData(result.rows, schema);
49
+ },
50
+ };
51
+ }
52
+ exports.wrapLegacyConnection = wrapLegacyConnection;
53
+ function valueToDate(value) {
54
+ // TODO properly map the data from BQ/Postgres types
55
+ if (value instanceof Date) {
56
+ return value;
57
+ }
58
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
+ const valAsAny = value;
60
+ if (valAsAny.constructor.name === 'Date') {
61
+ // For some reason duckdb TSTZ values come back as objects which do not
62
+ // pass "instance of" but do seem date like.
63
+ return new Date(value);
64
+ }
65
+ else if (typeof value === 'number') {
66
+ return new Date(value);
67
+ }
68
+ else if (typeof value !== 'string') {
69
+ return new Date(value.value);
70
+ }
71
+ else {
72
+ // Postgres timestamps end up here, and ideally we would know the system
73
+ // timezone of the postgres instance to correctly create a Date() object
74
+ // which represents the same instant in time, but we don't have the data
75
+ // flow to implement that. This may be a problem at some future day,
76
+ // so here is a comment, for that day.
77
+ let parsed = luxon_1.DateTime.fromISO(value, { zone: 'UTC' });
78
+ if (!parsed.isValid) {
79
+ parsed = luxon_1.DateTime.fromSQL(value, { zone: 'UTC' });
80
+ }
81
+ return parsed.toJSDate();
82
+ }
83
+ }
84
+ function mapData(data, schema) {
85
+ function mapValue(value, field) {
86
+ if (value === null) {
87
+ return { kind: 'null_cell' };
88
+ }
89
+ else if (field.type.kind === 'date_type' ||
90
+ field.type.kind === 'timestamp_type') {
91
+ const time_value = valueToDate(value).toISOString();
92
+ if (field.type.kind === 'date_type') {
93
+ return { kind: 'date_cell', date_value: time_value };
94
+ }
95
+ else {
96
+ return { kind: 'timestamp_cell', timestamp_value: time_value };
97
+ }
98
+ }
99
+ else if (field.type.kind === 'boolean_type') {
100
+ if (typeof value === 'number') {
101
+ return { kind: 'boolean_cell', boolean_value: value !== 0 };
102
+ }
103
+ if (typeof value !== 'boolean') {
104
+ throw new Error(`Invalid boolean ${value}`);
105
+ }
106
+ return { kind: 'boolean_cell', boolean_value: value };
107
+ }
108
+ else if (field.type.kind === 'number_type') {
109
+ if (typeof value !== 'number') {
110
+ throw new Error(`Invalid number ${value}`);
111
+ }
112
+ return { kind: 'number_cell', number_value: value };
113
+ }
114
+ else if (field.type.kind === 'string_type') {
115
+ if (typeof value !== 'string') {
116
+ throw new Error(`Invalid string ${value}`);
117
+ }
118
+ return { kind: 'string_cell', string_value: value };
119
+ }
120
+ else if (field.type.kind === 'array_type') {
121
+ if (!Array.isArray(value)) {
122
+ throw new Error(`Invalid array ${value}`);
123
+ }
124
+ return {
125
+ kind: 'array_cell',
126
+ array_value: value.map(value => mapValue(value, {
127
+ name: 'array_element',
128
+ type: field.type.element_type,
129
+ })),
130
+ };
131
+ }
132
+ else if (field.type.kind === 'json_type') {
133
+ return { kind: 'json_cell', json_value: JSON.stringify(value) };
134
+ }
135
+ else if (field.type.kind === 'sql_native_type') {
136
+ return { kind: 'sql_native_cell', sql_native_value: JSON.stringify(value) };
137
+ }
138
+ else {
139
+ const type = field.type;
140
+ if (type.kind !== 'record_type') {
141
+ throw new Error(`Invalid record in result ${JSON.stringify(field)}, ${JSON.stringify(value)}`);
142
+ }
143
+ return mapRow(value, {
144
+ kind: 'join',
145
+ relationship: 'many',
146
+ name: 'array_element',
147
+ schema: {
148
+ fields: type.fields.map(f => ({ kind: 'dimension', ...f })),
149
+ },
150
+ });
151
+ }
152
+ }
153
+ function mapRow(row, field) {
154
+ const cells = [];
155
+ for (const f of field.schema.fields) {
156
+ const value = row[f.name];
157
+ if (f.kind !== 'dimension') {
158
+ throw new Error('Invalid result -- expected all fields to be dimensions');
159
+ }
160
+ const cell = mapValue(value, f);
161
+ cells.push(cell);
162
+ }
163
+ return {
164
+ kind: 'record_cell',
165
+ record_value: cells,
166
+ };
167
+ }
168
+ const rootField = {
169
+ kind: 'join',
170
+ schema,
171
+ name: 'root',
172
+ relationship: 'one',
173
+ };
174
+ return {
175
+ kind: 'array_cell',
176
+ array_value: data.map(row => mapRow(row, rootField)),
177
+ };
178
+ }
179
+ exports.mapData = mapData;
180
+ function wrapResult(result) {
181
+ const structs = result._queryResult.structs;
182
+ const struct = structs[structs.length - 1];
183
+ const schema = { fields: (0, to_stable_1.convertFieldInfos)(struct, struct.fields) };
184
+ const annotations = (0, annotation_1.annotationToTaglines)(result.annotation).map(l => ({
185
+ value: l,
186
+ }));
187
+ const metadataAnnot = struct.resultMetadata
188
+ ? (0, to_stable_1.getResultStructMetadataAnnotation)(struct, struct.resultMetadata)
189
+ : undefined;
190
+ if (metadataAnnot) {
191
+ annotations.push(metadataAnnot);
192
+ }
193
+ annotations.push(...(struct.resultMetadata ? [] : []));
194
+ if (result.sourceExplore) {
195
+ annotations.push({
196
+ value: malloy_tag_1.Tag.withPrefix('#(malloy) ')
197
+ .set(['source_name'], result.sourceExplore.name)
198
+ .toString(),
199
+ });
200
+ }
201
+ annotations.push({
202
+ value: malloy_tag_1.Tag.withPrefix('#(malloy) ')
203
+ .set(['query_name'], result.resultExplore.name)
204
+ .toString(),
205
+ });
206
+ return {
207
+ schema,
208
+ data: mapData(result.data.toObject(), schema),
209
+ connection_name: result.connectionName,
210
+ annotations: annotations.length > 0 ? annotations : undefined,
211
+ query_timezone: result.data.field.queryTimezone,
212
+ };
213
+ }
214
+ exports.wrapResult = wrapResult;
215
+ //# sourceMappingURL=util.js.map
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { isSourceDef, Segment, isLeafAtomic, isJoined, isJoinedSource, isSamplin
5
5
  export { MalloyTranslator, } from './lang';
6
6
  export type { LogMessage, TranslateResponse } from './lang';
7
7
  export { Model, Malloy, Runtime, AtomicFieldType, ConnectionRuntime, SingleConnectionRuntime, EmptyURLReader, InMemoryURLReader, FixedConnectionMap, MalloyError, JoinRelationship, SourceRelationship, DateTimeframe, TimestampTimeframe, PreparedResult, Result, QueryMaterializer, CSVWriter, JSONWriter, Parse, DataWriter, Explore, InMemoryModelCache, CacheManager, } from './malloy';
8
- export type { PreparedQuery, Field, AtomicField, ExploreField, QueryField, SortableField, DataArray, DataRecord, DataColumn, DataArrayOrRecord, Loggable, ModelMaterializer, DocumentTablePath, DocumentSymbol, ResultJSON, PreparedResultMaterializer, ExploreMaterializer, WriteStream, SerializedExplore, ModelCache, CachedModel, DateField, TimestampField, } from './malloy';
8
+ export type { PreparedQuery, Field, AtomicField, ExploreField, QueryField, SortableField, DataArray, DataRecord, DataColumn, DataArrayOrRecord, Loggable, ModelMaterializer, DocumentTablePath, DocumentSymbol, ResultJSON, PreparedResultJSON, PreparedResultMaterializer, ExploreMaterializer, WriteStream, SerializedExplore, ModelCache, CachedModel, DateField, TimestampField, } from './malloy';
9
9
  export type { QueryOptionsReader, RunSQLOptions } from './run_sql_options';
10
10
  export type { EventStream, ModelString, ModelURL, QueryString, QueryURL, URLReader, InvalidationKey, } from './runtime_types';
11
11
  export type { Connection, ConnectionConfig, ConnectionFactory, ConnectionParameter, ConnectionParameterValue, ConnectionConfigSchema, FetchSchemaOptions, InfoConnection, LookupConnection, PersistSQLResults, PooledConnection, TestableConnection, StreamingConnection, } from './connection/types';
@@ -1,12 +1,4 @@
1
- import { CodePointCharStream, CommonTokenStream, ParserRuleContext } from 'antlr4ts';
2
- import { ParseTree } from 'antlr4ts/tree';
3
- import { DocumentRange } from '../model/malloy_types';
4
- export interface MalloyParseInfo {
5
- root: ParseTree;
6
- tokenStream: CommonTokenStream;
7
- sourceStream: CodePointCharStream;
8
- sourceURL: string;
1
+ import { ParseInfo } from './utils';
2
+ export interface MalloyParseInfo extends ParseInfo {
9
3
  importBaseURL: string;
10
- rangeFromContext: (pcx: ParserRuleContext) => DocumentRange;
11
- malloyVersion: string;
12
4
  }
@@ -44,6 +44,7 @@ export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElem
44
44
  * Log an error message relative to an AST node
45
45
  */
46
46
  protected astError<T extends MessageCode>(el: ast.MalloyElement, code: T, data: MessageParameterType<T>, options?: LogMessageOptions): void;
47
+ protected rangeFromContext(cx: ParserRuleContext): DocumentRange;
47
48
  protected getLocation(cx: ParserRuleContext): DocumentLocation;
48
49
  protected getSourceString(cx: ParserRuleContext): string;
49
50
  /**
@@ -105,10 +105,13 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
105
105
  astError(el, code, data, options) {
106
106
  this.msgLog.log((0, parse_log_1.makeLogMessage)(code, data, { at: el.location, ...options }));
107
107
  }
108
+ rangeFromContext(cx) {
109
+ return (0, utils_1.rangeFromContext)(this.parseInfo.sourceInfo, cx);
110
+ }
108
111
  getLocation(cx) {
109
112
  return {
110
113
  url: this.parseInfo.sourceURL,
111
- range: this.parseInfo.rangeFromContext(cx),
114
+ range: this.rangeFromContext(cx),
112
115
  };
113
116
  }
114
117
  getSourceString(cx) {
@@ -180,7 +183,7 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
180
183
  astAt(el, cx) {
181
184
  el.location = {
182
185
  url: this.parseInfo.sourceURL,
183
- range: this.parseInfo.rangeFromContext(cx),
186
+ range: this.rangeFromContext(cx),
184
187
  };
185
188
  return el;
186
189
  }
@@ -957,7 +960,7 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
957
960
  const left = this.getFieldExpr(pcx.fieldExpr(0));
958
961
  const right = this.getFieldExpr(pcx.fieldExpr(1));
959
962
  if (ast.isEquality(op)) {
960
- const wholeRange = this.parseInfo.rangeFromContext(pcx);
963
+ const wholeRange = this.rangeFromContext(pcx);
961
964
  if (right instanceof ast.ExprNULL) {
962
965
  if (op === '=') {
963
966
  this.warnWithReplacement('sql-is-null', "Use 'is null' to check for NULL instead of '= null'", wholeRange, `${this.getSourceCode(pcx.fieldExpr(0))} is null`);
@@ -1170,7 +1173,7 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1170
1173
  });
1171
1174
  const elseCx = pcx._caseElse;
1172
1175
  const theElse = elseCx ? this.getFieldExpr(elseCx) : undefined;
1173
- this.warnWithReplacement('sql-case', 'Use a `pick` statement instead of `case`', this.parseInfo.rangeFromContext(pcx), `${[
1176
+ this.warnWithReplacement('sql-case', 'Use a `pick` statement instead of `case`', this.rangeFromContext(pcx), `${[
1174
1177
  ...(valueCx ? [`${this.getSourceCode(valueCx)} ?`] : []),
1175
1178
  ...whenCxs.map(whenCx => `pick ${this.getSourceCode(whenCx._result)} when ${this.getSourceCode(whenCx._condition)}`),
1176
1179
  elseCx ? `else ${elseCx.text}` : 'else null',
@@ -1486,7 +1489,7 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1486
1489
  let op = '~';
1487
1490
  const left = pcx.fieldExpr(0);
1488
1491
  const right = pcx.fieldExpr(1);
1489
- const wholeRange = this.parseInfo.rangeFromContext(pcx);
1492
+ const wholeRange = this.rangeFromContext(pcx);
1490
1493
  if (pcx.NOT()) {
1491
1494
  op = '!~';
1492
1495
  this.warnWithReplacement('sql-not-like', "Use Malloy operator '!~' instead of 'NOT LIKE'", wholeRange, `${this.getSourceCode(left)} !~ ${this.getSourceCode(right)}`);
@@ -1505,7 +1508,7 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
1505
1508
  const isNot = !!pcx.NOT();
1506
1509
  const from = pcx.fieldExprList().fieldExpr();
1507
1510
  const inStmt = this.astAt(new ast.ExprLegacyIn(expr, isNot, from.map(f => this.getFieldExpr(f))), pcx);
1508
- this.warnWithReplacement('sql-in', `Use = (a|b|c) instead of${isNot ? ' NOT' : ''} IN (a,b,c)`, this.parseInfo.rangeFromContext(pcx), `${this.getSourceCode(pcx.fieldExpr())} ${isNot ? '!=' : '='} (${from
1511
+ this.warnWithReplacement('sql-in', `Use = (a|b|c) instead of${isNot ? ' NOT' : ''} IN (a,b,c)`, this.rangeFromContext(pcx), `${this.getSourceCode(pcx.fieldExpr())} ${isNot ? '!=' : '='} (${from
1509
1512
  .map(f => this.getSourceCode(f))
1510
1513
  .join(' | ')})`);
1511
1514
  return inStmt;
@@ -0,0 +1,76 @@
1
+ import { ParserRuleContext } from 'antlr4ts';
2
+ import { ParseTree, TerminalNode } from 'antlr4ts/tree';
3
+ import { AbstractParseTreeVisitor } from 'antlr4ts/tree/AbstractParseTreeVisitor';
4
+ import { MalloyParserVisitor } from './lib/Malloy/MalloyParserVisitor';
5
+ import * as Malloy from '@malloydata/malloy-interfaces';
6
+ import * as parse from './lib/Malloy/MalloyParser';
7
+ import { LogMessageOptions, MessageCode, MessageLogger, MessageParameterType } from './parse-log';
8
+ import { DocumentLocation } from '../model/malloy_types';
9
+ import { ParseInfo } from './utils';
10
+ type HasAnnotations = ParserRuleContext & {
11
+ ANNOTATION: () => TerminalNode[];
12
+ };
13
+ type Node = Malloy.Query | Malloy.QueryDefinitionWithArrow | Malloy.QueryDefinitionWithQueryReference | Malloy.QueryDefinitionWithRefinement | null;
14
+ /**
15
+ * ANTLR visitor pattern parse tree traversal. Generates a Malloy
16
+ * AST from an ANTLR parse tree.
17
+ */
18
+ export declare class MalloyToQuery extends AbstractParseTreeVisitor<Node> implements MalloyParserVisitor<Node> {
19
+ readonly parseInfo: ParseInfo;
20
+ readonly msgLog: MessageLogger;
21
+ constructor(parseInfo: ParseInfo, msgLog: MessageLogger);
22
+ /**
23
+ * Mostly used to flag a case where the grammar and the type system are
24
+ * no longer in sync. A visitor was written based on a grammar which
25
+ * apparently has changed and now an unexpected element type has appeared.
26
+ * This is a non recoverable error, since the parser and the grammar
27
+ * are not compatible.
28
+ * @return an error object to throw.
29
+ */
30
+ protected internalError(cx: ParserRuleContext, message: string): Error;
31
+ protected getLocation(cx: ParserRuleContext): DocumentLocation;
32
+ /**
33
+ * Log an error message relative to a parse node
34
+ */
35
+ protected contextError<T extends MessageCode>(cx: ParserRuleContext, code: T, data: MessageParameterType<T>, options?: LogMessageOptions): void;
36
+ protected getNumber(term: ParseTree): number;
37
+ protected defaultResult(): Node;
38
+ /**
39
+ * Get all the possibly missing annotations from this parse rule
40
+ * @param cx Any parse context which has an ANNOTATION* rules
41
+ * @returns Array of texts for the annotations
42
+ */
43
+ protected getAnnotations(cx: HasAnnotations): Malloy.Annotation[] | undefined;
44
+ protected getIsAnnotations(cx?: parse.IsDefineContext): Malloy.Annotation[] | undefined;
45
+ protected notAllowed(pcx: ParserRuleContext, what: string): void;
46
+ protected illegal(pcx: ParserRuleContext, what: string): void;
47
+ visitMalloyDocument(pcx: parse.MalloyDocumentContext): Malloy.Query | null;
48
+ visitRunStatement(pcx: parse.RunStatementContext): Malloy.Query | null;
49
+ protected getQueryReference(cx: parse.SQIDContext): Malloy.Reference | null;
50
+ protected getQueryDefinition(cx: parse.SqExprContext): Malloy.QueryDefinition | null;
51
+ protected getRefinementSegment(cx: parse.SegExprContext): Malloy.ViewDefinition | null;
52
+ protected getGroupByStatement(gbcx: parse.GroupByStatementContext): Malloy.ViewOperationWithGroupBy[] | null;
53
+ protected getAggregateStatement(agcx: parse.AggregateStatementContext): Malloy.ViewOperationWithAggregate[] | null;
54
+ protected getOrderByStatement(obcx: parse.OrderByStatementContext): Malloy.ViewOperationWithOrderBy[] | null;
55
+ protected getNestStatement(nstcx: parse.NestStatementContext): Malloy.ViewOperationWithNest[] | null;
56
+ protected getViewExpression(cx: parse.VExprContext): Malloy.ViewDefinition | null;
57
+ protected getLimitStatement(cx: parse.LimitStatementContext): Malloy.ViewOperationWithLimit | null;
58
+ protected getSegmentOperation(cx: parse.QueryStatementContext): Malloy.ViewOperation[] | null;
59
+ protected getFieldPath(pcx: parse.FieldPathContext): {
60
+ name: string;
61
+ path?: string[];
62
+ };
63
+ protected getTimeframe(cx: parse.TimeframeContext): Malloy.TimestampTimeframe | null;
64
+ protected getQueryField(cx: parse.QueryFieldEntryContext): {
65
+ name?: string;
66
+ field: Malloy.Field;
67
+ } | null;
68
+ getFieldExpression(cx: parse.FieldExprContext): Malloy.Expression | null;
69
+ getWhere(_whereCx: parse.WhereStatementContext): Malloy.Where[] | null;
70
+ protected combineAnnotations(...a: (Malloy.Annotation[] | undefined)[]): Malloy.Annotation[] | undefined;
71
+ }
72
+ export declare function malloyToQuery(code: string): {
73
+ query?: Malloy.Query;
74
+ logs: Malloy.LogMessage[];
75
+ };
76
+ export {};