@malloydata/malloy 0.0.2 → 0.0.3

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 (46) hide show
  1. package/README.md +12 -11
  2. package/dist/dialect/duckdb.d.ts +1 -1
  3. package/dist/dialect/duckdb.js +35 -37
  4. package/dist/dialect/postgres.d.ts +1 -1
  5. package/dist/dialect/postgres.js +15 -8
  6. package/dist/dialect/standardsql.js +1 -0
  7. package/dist/index.d.ts +4 -4
  8. package/dist/index.js +2 -2
  9. package/dist/lang/ast/apply-expr.js +2 -2
  10. package/dist/lang/ast/ast-expr.js +2 -12
  11. package/dist/lang/ast/ast-main.d.ts +2 -2
  12. package/dist/lang/ast/ast-main.js +2 -1
  13. package/dist/lang/field-space.d.ts +9 -7
  14. package/dist/lang/field-space.js +10 -8
  15. package/dist/lang/lib/Malloy/MalloyLexer.d.ts +108 -106
  16. package/dist/lang/lib/Malloy/MalloyLexer.js +1019 -1006
  17. package/dist/lang/lib/Malloy/MalloyParser.d.ts +581 -590
  18. package/dist/lang/lib/Malloy/MalloyParser.js +1141 -1202
  19. package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +2015 -0
  20. package/dist/lang/lib/Malloy/MalloyParserListener.js +4 -0
  21. package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +1269 -0
  22. package/dist/lang/lib/Malloy/MalloyParserVisitor.js +4 -0
  23. package/dist/lang/parse-to-ast.d.ts +3 -4
  24. package/dist/lang/parse-to-ast.js +1 -1
  25. package/dist/lang/parse-tree-walkers/document-completion-walker.js +2 -0
  26. package/dist/lang/parse-tree-walkers/explore-query-walker.d.ts +2 -2
  27. package/dist/lang/test/field-symbols.spec.js +2 -2
  28. package/dist/lang/test/parse.spec.js +15 -0
  29. package/dist/lang/test/test-translator.js +1 -1
  30. package/dist/malloy.d.ts +1 -1
  31. package/dist/malloy.js +11 -5
  32. package/dist/md5.d.ts +1 -0
  33. package/dist/md5.js +30 -0
  34. package/dist/model/malloy_query.js +4 -6
  35. package/dist/model/malloy_types.d.ts +3 -1
  36. package/package.json +9 -14
  37. package/dist/dialect/dialect-map.d.ts +0 -3
  38. package/dist/dialect/dialect-map.js +0 -33
  39. package/dist/model/malloy-query.d.ts +0 -313
  40. package/dist/model/malloy-query.js +0 -2603
  41. package/dist/model/malloy-types.d.ts +0 -404
  42. package/dist/model/malloy-types.js +0 -242
  43. package/dist/model/sql-block.d.ts +0 -11
  44. package/dist/model/sql-block.js +0 -38
  45. package/dist/runtime-types.d.ts +0 -116
  46. package/dist/runtime-types.js +0 -40
package/README.md CHANGED
@@ -9,17 +9,16 @@ This package facilitates building the Malloy language - or the usage of data mod
9
9
  ## Show me an example!
10
10
 
11
11
  ```
12
- import { Runtime } from "@malloydata/malloy";
13
- import { DuckDBConnection } from "@malloydata/db-duckdb";
14
-
15
- const connection = new DuckDBConnection("duckdb-example");
16
- const runtime = new Runtime(files, connection);
17
-
18
- runtime.loadModel("source: flights is table('duckdb:data/flights.parquet')")
19
-
20
- const runner = runtime.loadQuery("query: flights->{group_by: flight_num}")
21
- runner.run() // <- executes query, returns JSON of results
22
-
12
+ const malloy = require("@malloydata/malloy")
13
+ const bigquery = require("@malloydata/db-bigquery")
14
+
15
+ const connection = new bigquery.BigQueryConnection("bigquery");
16
+ const runtime = new malloy.SingleConnectionRuntime(connection);
17
+ const model = runtime.loadModel("source: airports is table('malloytest.airports')")
18
+ const runner = model.loadQuery("query: airports->{aggregate: airport_count is count()}")
19
+ runner.run().then((result) => {
20
+ console.log(result.data.value) // [ { airport_count: 19793 } ]
21
+ })
23
22
  ```
24
23
 
25
24
  Note: These APIs are still in beta and subject to change.
@@ -37,3 +36,5 @@ In practice, much of this loop is handled by various database plugins:
37
36
  ## Do you have any examples?
38
37
 
39
38
  You can find a (very) simple example of writing a CLI for executing Malloy queries [here](https://github.com/looker-open-source/malloy/tree/main/demo/malloy-demo-bq-cli)
39
+
40
+ A more realistic and complex use case - we use these libraries to power our VSCode Extension. Some examples can be found [here](https://github.com/looker-open-source/malloy/tree/main/vscode-extension/src/extension/commands)
@@ -34,7 +34,7 @@ export declare class DuckDBDialect extends Dialect {
34
34
  sqlSelectAliasAsStruct(alias: string, physicalFieldNames: string[]): string;
35
35
  sqlMaybeQuoteIdentifier(identifier: string): string;
36
36
  sqlCreateTableAsSelect(_tableName: string, _sql: string): string;
37
- getFunctionInfo(_functionName: string): FunctionInfo | undefined;
37
+ getFunctionInfo(functionName: string): FunctionInfo | undefined;
38
38
  sqlMeasureTime(from: TimeValue, to: TimeValue, units: string): Expr;
39
39
  sqlNow(): Expr;
40
40
  sqlTrunc(sqlTime: TimeValue, units: TimestampUnit): Expr;
@@ -109,8 +109,6 @@ const inSeconds = {
109
109
  second: 1,
110
110
  minute: 60,
111
111
  hour: 3600,
112
- day: 86400,
113
- week: 604800,
114
112
  };
115
113
  class DuckDBDialect extends dialect_1.Dialect {
116
114
  constructor() {
@@ -125,7 +123,9 @@ class DuckDBDialect extends dialect_1.Dialect {
125
123
  this.defaultSampling = { rows: 50000 };
126
124
  this.supportUnnestArrayAgg = true;
127
125
  this.supportsCTEinCoorelatedSubQueries = true;
128
- this.functionInfo = {};
126
+ this.functionInfo = {
127
+ concat: { returnType: "string" },
128
+ };
129
129
  }
130
130
  // hack until they support temporary macros.
131
131
  get udfPrefix() {
@@ -230,8 +230,8 @@ class DuckDBDialect extends dialect_1.Dialect {
230
230
  sqlCreateTableAsSelect(_tableName, _sql) {
231
231
  throw new Error("Not implemented Yet");
232
232
  }
233
- getFunctionInfo(_functionName) {
234
- return undefined;
233
+ getFunctionInfo(functionName) {
234
+ return this.functionInfo[functionName];
235
235
  }
236
236
  sqlMeasureTime(from, to, units) {
237
237
  let lVal = from.value;
@@ -242,21 +242,20 @@ class DuckDBDialect extends dialect_1.Dialect {
242
242
  const duration = (0, model_1.mkExpr) `(${rVal} - ${lVal})`;
243
243
  return units == "second"
244
244
  ? duration
245
- : (0, model_1.mkExpr) `TRUNC(${duration}/${inSeconds[units].toString()})`;
245
+ : (0, model_1.mkExpr) `FLOOR(${duration}/${inSeconds[units].toString()})`;
246
246
  }
247
- const yearDiff = (0, model_1.mkExpr) `TRUNC(EXTRACT(YEAR FROM ${rVal}) - EXTRACT(YEAR FROM ${lVal}))`;
248
- if (units == "year") {
249
- return yearDiff;
247
+ if (from.valueType != "date") {
248
+ lVal = (0, model_1.mkExpr) `CAST((${lVal}) AS DATE)`;
250
249
  }
251
- if (units == "month") {
252
- const monthDiff = (0, model_1.mkExpr) `TRUNC(EXTRACT(MONTH FROM ${rVal}) - EXTRACT(MONTH FROM ${lVal}))`;
253
- return (0, model_1.mkExpr) `${yearDiff} * 12 + ${monthDiff}`;
250
+ if (to.valueType != "date") {
251
+ rVal = (0, model_1.mkExpr) `CAST((${rVal}) AS DATE)`;
254
252
  }
255
- if (units == "quarter") {
256
- const qDiff = (0, model_1.mkExpr) `TRUNC(EXTRACT(QUARTER FROM ${rVal}) - EXTRACT(QUARTER FROM ${lVal}))`;
257
- return (0, model_1.mkExpr) `${yearDiff} * 4 + ${qDiff}`;
253
+ if (units == "week") {
254
+ // DuckDB's weeks start on Monday, but Malloy's weeks start on Sunday
255
+ lVal = (0, model_1.mkExpr) `(${lVal} + INTERVAL 1 DAY)`;
256
+ rVal = (0, model_1.mkExpr) `(${rVal} + INTERVAL 1 DAY)`;
258
257
  }
259
- throw new Error(`Unknown or unhandled postgres time unit: ${units}`);
258
+ return (0, model_1.mkExpr) `DATE_DIFF('${units}', ${lVal}, ${rVal})`;
260
259
  }
261
260
  sqlNow() {
262
261
  return (0, model_1.mkExpr) `CURRENT_TIMESTAMP`;
@@ -265,10 +264,10 @@ class DuckDBDialect extends dialect_1.Dialect {
265
264
  // adjusting for monday/sunday weeks
266
265
  const week = units == "week";
267
266
  const truncThis = week
268
- ? (0, model_1.mkExpr) `${sqlTime.value}+interval'1'day`
267
+ ? (0, model_1.mkExpr) `${sqlTime.value} + INTERVAL 1 DAY`
269
268
  : sqlTime.value;
270
269
  const trunced = (0, model_1.mkExpr) `DATE_TRUNC('${units}', ${truncThis})`;
271
- return week ? (0, model_1.mkExpr) `(${trunced}-interval'1'day)` : trunced;
270
+ return week ? (0, model_1.mkExpr) `(${trunced} - INTERVAL 1 DAY)` : trunced;
272
271
  }
273
272
  sqlExtract(from, units) {
274
273
  const pgUnits = pgExtractionMap[units] || units;
@@ -284,8 +283,8 @@ class DuckDBDialect extends dialect_1.Dialect {
284
283
  timeframe = "day";
285
284
  n = (0, model_1.mkExpr) `${n}*7`;
286
285
  }
287
- const interval = (0, model_1.mkExpr) `INTERVAL ${n} ${timeframe}`;
288
- return (0, model_1.mkExpr) `((${expr.value})${op}${interval})`;
286
+ const interval = (0, model_1.mkExpr) `INTERVAL (${n}) ${timeframe}`;
287
+ return (0, model_1.mkExpr) `((${expr.value})) ${op} ${interval}`;
289
288
  }
290
289
  sqlCast(cast) {
291
290
  if (cast.dstType !== cast.srcType) {
@@ -299,7 +298,7 @@ class DuckDBDialect extends dialect_1.Dialect {
299
298
  }
300
299
  sqlLiteralTime(timeString, type, _timezone) {
301
300
  if (type == "date") {
302
- return `DATE('${timeString}')`;
301
+ return `DATE '${timeString}'`;
303
302
  }
304
303
  else if (type == "timestamp") {
305
304
  return `TIMESTAMP '${timeString}'`;
@@ -308,24 +307,23 @@ class DuckDBDialect extends dialect_1.Dialect {
308
307
  throw new Error(`Unknown Literal time format ${type}`);
309
308
  }
310
309
  }
311
- // sqlSumDistinct(key: string, value: string): string {
312
- // // return `sum_distinct(list({key:${key}, val: ${value}}))`;
313
- // return `(
314
- // fail -- force the query for fail until the bug is fixed.
315
- // SELECT sum(a.val) as value
316
- // FROM (
317
- // SELECT UNNEST(list(distinct {key:${key}, val: ${value}})) a
318
- // )
319
- // )`;
320
- // }
321
310
  sqlSumDistinct(key, value) {
322
- const _factor = 32;
323
- const precision = 0.000001;
324
- const keySQL = `md5_number_lower(${key}::varchar)::int128`;
325
- return `
326
- (SUM(DISTINCT ${keySQL} + FLOOR(IFNULL(${value},0)/${precision})::int128) - SUM(DISTINCT ${keySQL}))*${precision}
327
- `;
311
+ // return `sum_distinct(list({key:${key}, val: ${value}}))`;
312
+ return `(
313
+ SELECT sum(a.val) as value
314
+ FROM (
315
+ SELECT UNNEST(list(distinct {key:${key}, val: ${value}})) a
316
+ )
317
+ )`;
328
318
  }
319
+ // sqlSumDistinct(key: string, value: string): string {
320
+ // const _factor = 32;
321
+ // const precision = 0.000001;
322
+ // const keySQL = `md5_number_lower(${key}::varchar)::int128`;
323
+ // return `
324
+ // (SUM(DISTINCT ${keySQL} + FLOOR(IFNULL(${value},0)/${precision})::int128) - SUM(DISTINCT ${keySQL}))*${precision}
325
+ // `;
326
+ // }
329
327
  // default duckdb to sampling 50K rows.
330
328
  sqlSampleTable(tableSQL, sample) {
331
329
  if (sample !== undefined) {
@@ -41,7 +41,7 @@ export declare class PostgresDialect extends Dialect {
41
41
  sqlCast(cast: TypecastFragment): Expr;
42
42
  sqlRegexpMatch(expr: Expr, regexp: string): Expr;
43
43
  sqlLiteralTime(timeString: string, type: TimeFieldType, _timezone: string): string;
44
- getFunctionInfo(_functionName: string): FunctionInfo | undefined;
44
+ getFunctionInfo(functionName: string): FunctionInfo | undefined;
45
45
  sqlMeasureTime(from: TimeValue, to: TimeValue, units: string): Expr;
46
46
  sqlSumDistinct(key: string, value: string): string;
47
47
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
@@ -37,8 +37,6 @@ const inSeconds = {
37
37
  second: 1,
38
38
  minute: 60,
39
39
  hour: 3600,
40
- day: 86400,
41
- week: 604800,
42
40
  };
43
41
  class PostgresDialect extends dialect_1.Dialect {
44
42
  constructor() {
@@ -54,7 +52,9 @@ class PostgresDialect extends dialect_1.Dialect {
54
52
  this.defaultSampling = { rows: 50000 };
55
53
  this.supportUnnestArrayAgg = true;
56
54
  this.supportsCTEinCoorelatedSubQueries = true;
57
- this.functionInfo = {};
55
+ this.functionInfo = {
56
+ concat: { returnType: "string" },
57
+ };
58
58
  }
59
59
  quoteTablePath(tablePath) {
60
60
  return tablePath
@@ -249,8 +249,8 @@ class PostgresDialect extends dialect_1.Dialect {
249
249
  throw new Error(`Unknown Literal time format ${type}`);
250
250
  }
251
251
  }
252
- getFunctionInfo(_functionName) {
253
- return undefined;
252
+ getFunctionInfo(functionName) {
253
+ return this.functionInfo[functionName];
254
254
  }
255
255
  sqlMeasureTime(from, to, units) {
256
256
  let lVal = from.value;
@@ -263,16 +263,23 @@ class PostgresDialect extends dialect_1.Dialect {
263
263
  ? duration
264
264
  : (0, model_1.mkExpr) `TRUNC(${duration}/${inSeconds[units].toString()})`;
265
265
  }
266
- const yearDiff = (0, model_1.mkExpr) `TRUNC(EXTRACT(YEAR FROM ${rVal}) - EXTRACT(YEAR FROM ${lVal}))`;
266
+ if (units === "day") {
267
+ return (0, model_1.mkExpr) `${rVal}::date - ${lVal}::date`;
268
+ }
269
+ const yearDiff = (0, model_1.mkExpr) `(DATE_PART('year', ${rVal}) - DATE_PART('year', ${lVal}))`;
267
270
  if (units == "year") {
268
271
  return yearDiff;
269
272
  }
273
+ if (units == "week") {
274
+ const dayDiffForWeekStart = (0, model_1.mkExpr) `(DATE_TRUNC('week', ${rVal} + '1 day'::interval)::date - DATE_TRUNC('week', ${lVal} + '1 day'::interval)::date)`;
275
+ return (0, model_1.mkExpr) `${dayDiffForWeekStart} / 7`;
276
+ }
270
277
  if (units == "month") {
271
- const monthDiff = (0, model_1.mkExpr) `TRUNC(EXTRACT(MONTH FROM ${rVal}) - EXTRACT(MONTH FROM ${lVal}))`;
278
+ const monthDiff = (0, model_1.mkExpr) `DATE_PART('month', ${rVal}) - DATE_PART('month', ${lVal})`;
272
279
  return (0, model_1.mkExpr) `${yearDiff} * 12 + ${monthDiff}`;
273
280
  }
274
281
  if (units == "quarter") {
275
- const qDiff = (0, model_1.mkExpr) `TRUNC(EXTRACT(QUARTER FROM ${rVal}) - EXTRACT(QUARTER FROM ${lVal}))`;
282
+ const qDiff = (0, model_1.mkExpr) `DATE_PART('quarter', ${rVal}) - DATE_PART('quarter', ${lVal})`;
276
283
  return (0, model_1.mkExpr) `${yearDiff} * 4 + ${qDiff}`;
277
284
  }
278
285
  throw new Error(`Unknown or unhandled postgres time unit: ${units}`);
@@ -48,6 +48,7 @@ class StandardSQLDialect extends dialect_1.Dialect {
48
48
  this.supportsCTEinCoorelatedSubQueries = false;
49
49
  this.functionInfo = {
50
50
  timestamp_seconds: { returnType: "timestamp" },
51
+ concat: { returnType: "string" },
51
52
  };
52
53
  this.keywords = `
53
54
  ALL
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export type { QueryDataRow, ModelDef, Fragment, Query, StructDef, NamedStructDefs, MalloyQueryData, AtomicFieldType as AtomicFieldTypeInner, DateUnit, ExtractUnit, TimestampUnit, TimeFieldType, QueryData, FieldTypeDef, Expr, DialectFragment, TimeValue, FilterExpression, SQLBlock, FieldDef, PipeSegment, QueryFieldDef, TurtleDef, SearchValueMapResult, SearchIndexResult, } from "./model";
1
+ export type { QueryDataRow, ModelDef, Fragment, Query, StructDef, StructRelationship, NamedStructDefs, MalloyQueryData, AtomicFieldType as AtomicFieldTypeInner, DateUnit, ExtractUnit, TimestampUnit, TimeFieldType, QueryData, FieldTypeDef, Expr, DialectFragment, TimeValue, FilterExpression, SQLBlock, FieldDef, FilteredAliasedName, PipeSegment, QueryFieldDef, TurtleDef, SearchValueMapResult, SearchIndexResult, } from "./model";
2
2
  export { Segment, isFilteredAliasedName, } from "./model";
3
3
  export { HighlightType, MalloyTranslator, } from "./lang";
4
4
  export type { LogMessage, TranslateResponse } from "./lang";
5
- export { Malloy, Runtime, AtomicFieldType, ConnectionRuntime, SingleConnectionRuntime, EmptyURLReader, InMemoryURLReader, FixedConnectionMap, MalloyError, JoinRelationship, SourceRelationship, DateTimeframe, TimestampTimeframe, Result, parseTableURL, QueryMaterializer, CSVWriter, JSONWriter, DataWriter, } from "./malloy";
6
- export type { Explore, Model, PreparedQuery, PreparedResult, Field, AtomicField, ExploreField, QueryField, DataArray, DataRecord, DataColumn, DataArrayOrRecord, ModelMaterializer, DocumentSymbol, DocumentHighlight, ResultJSON, PreparedResultMaterializer, SQLBlockMaterializer, ExploreMaterializer, WriteStream, } from "./malloy";
7
- export type { URLReader, InfoConnection, LookupConnection, Connection, QueryString, ModelString, QueryURL, ModelURL, PooledConnection, TestableConnection, PersistSQLResults, } from "./runtime_types";
5
+ export { Malloy, Runtime, AtomicFieldType, ConnectionRuntime, SingleConnectionRuntime, EmptyURLReader, InMemoryURLReader, FixedConnectionMap, MalloyError, JoinRelationship, SourceRelationship, DateTimeframe, TimestampTimeframe, Result, parseTableURI, QueryMaterializer, CSVWriter, JSONWriter, DataWriter, } from "./malloy";
6
+ export type { Explore, Model, PreparedQuery, PreparedResult, Field, AtomicField, ExploreField, QueryField, DataArray, DataRecord, DataColumn, DataArrayOrRecord, ModelMaterializer, DocumentSymbol, DocumentHighlight, ResultJSON, RunSQLOptions, PreparedResultMaterializer, SQLBlockMaterializer, ExploreMaterializer, WriteStream, } from "./malloy";
7
+ export type { URLReader, InfoConnection, LookupConnection, Connection, QueryString, ModelString, QueryURL, ModelURL, PooledConnection, TestableConnection, PersistSQLResults, FetchSchemaAndRunSimultaneously, StreamingConnection, FetchSchemaAndRunStreamSimultaneously, } from "./runtime_types";
8
8
  export type { Loggable } from "./malloy";
9
9
  export { toAsyncGenerator } from "./connection_utils";
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@
12
12
  * GNU General Public License for more details.
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.toAsyncGenerator = exports.DataWriter = exports.JSONWriter = exports.CSVWriter = exports.QueryMaterializer = exports.parseTableURL = exports.Result = exports.TimestampTimeframe = exports.DateTimeframe = exports.SourceRelationship = exports.JoinRelationship = exports.MalloyError = exports.FixedConnectionMap = exports.InMemoryURLReader = exports.EmptyURLReader = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.AtomicFieldType = exports.Runtime = exports.Malloy = exports.MalloyTranslator = exports.HighlightType = exports.isFilteredAliasedName = exports.Segment = void 0;
15
+ exports.toAsyncGenerator = exports.DataWriter = exports.JSONWriter = exports.CSVWriter = exports.QueryMaterializer = exports.parseTableURI = exports.Result = exports.TimestampTimeframe = exports.DateTimeframe = exports.SourceRelationship = exports.JoinRelationship = exports.MalloyError = exports.FixedConnectionMap = exports.InMemoryURLReader = exports.EmptyURLReader = exports.SingleConnectionRuntime = exports.ConnectionRuntime = exports.AtomicFieldType = exports.Runtime = exports.Malloy = exports.MalloyTranslator = exports.HighlightType = exports.isFilteredAliasedName = exports.Segment = void 0;
16
16
  var model_1 = require("./model");
17
17
  // Used in Composer Demo
18
18
  Object.defineProperty(exports, "Segment", { enumerable: true, get: function () { return model_1.Segment; } });
@@ -37,7 +37,7 @@ Object.defineProperty(exports, "SourceRelationship", { enumerable: true, get: fu
37
37
  Object.defineProperty(exports, "DateTimeframe", { enumerable: true, get: function () { return malloy_1.DateTimeframe; } });
38
38
  Object.defineProperty(exports, "TimestampTimeframe", { enumerable: true, get: function () { return malloy_1.TimestampTimeframe; } });
39
39
  Object.defineProperty(exports, "Result", { enumerable: true, get: function () { return malloy_1.Result; } });
40
- Object.defineProperty(exports, "parseTableURL", { enumerable: true, get: function () { return malloy_1.parseTableURL; } });
40
+ Object.defineProperty(exports, "parseTableURI", { enumerable: true, get: function () { return malloy_1.parseTableURI; } });
41
41
  Object.defineProperty(exports, "QueryMaterializer", { enumerable: true, get: function () { return malloy_1.QueryMaterializer; } });
42
42
  Object.defineProperty(exports, "CSVWriter", { enumerable: true, get: function () { return malloy_1.CSVWriter; } });
43
43
  Object.defineProperty(exports, "JSONWriter", { enumerable: true, get: function () { return malloy_1.JSONWriter; } });
@@ -43,10 +43,10 @@ function applyBinary(fs, left, op, right) {
43
43
  const num = left.getExpression(fs);
44
44
  const denom = right.getExpression(fs);
45
45
  if (num.dataType != "number") {
46
- left.log("Numerator for division mus tbe a number");
46
+ left.log("Numerator for division must be a number");
47
47
  }
48
48
  else if (denom.dataType != "number") {
49
- right.log("Denominator for division mus tbe a number");
49
+ right.log("Denominator for division must be a number");
50
50
  }
51
51
  else {
52
52
  const div = {
@@ -96,20 +96,10 @@ class ConstantFieldSpace {
96
96
  this.type = "fieldSpace";
97
97
  }
98
98
  structDef() {
99
- return {
100
- type: "struct",
101
- name: "empty structdef",
102
- structSource: { type: "table" },
103
- structRelationship: {
104
- type: "basetable",
105
- connectionName: "noConnection",
106
- },
107
- fields: [],
108
- dialect: "noDialect",
109
- };
99
+ throw new Error("ConstantFieldSpace cannot generate a structDef");
110
100
  }
111
101
  emptyStructDef() {
112
- return { ...this.structDef(), fields: [] };
102
+ throw new Error("ConstantFieldSpace cannot generate a structDef");
113
103
  }
114
104
  lookup(_name) {
115
105
  return {
@@ -303,9 +303,9 @@ export declare class WildcardFieldReference extends MalloyElement {
303
303
  }
304
304
  export declare class OrderBy extends MalloyElement {
305
305
  readonly field: number | FieldName;
306
- readonly dir?: "asc" | "desc" | undefined;
306
+ readonly dir?: "desc" | "asc" | undefined;
307
307
  elementType: string;
308
- constructor(field: number | FieldName, dir?: "asc" | "desc" | undefined);
308
+ constructor(field: number | FieldName, dir?: "desc" | "asc" | undefined);
309
309
  get modelField(): string | number;
310
310
  getOrderBy(_fs: FieldSpace): model.OrderBy;
311
311
  }
@@ -55,7 +55,7 @@ const theErrorStruct = {
55
55
  type: "struct",
56
56
  name: "~malformed~",
57
57
  dialect: "~malformed~",
58
- structSource: { type: "table" },
58
+ structSource: { type: "table", tablePath: "//undefined_error_table_path" },
59
59
  structRelationship: {
60
60
  type: "basetable",
61
61
  connectionName: "//undefined_error_connection",
@@ -867,6 +867,7 @@ class ExpressionJoin extends Join {
867
867
  if (sourceDef.structSource.type === "query") {
868
868
  // the name from query does not need to be preserved
869
869
  joinStruct.name = this.name.refString;
870
+ delete joinStruct.as;
870
871
  }
871
872
  else {
872
873
  joinStruct.as = this.name.refString;
@@ -48,10 +48,10 @@ export declare type SourceSpec = model.StructDef | FieldSpace;
48
48
  /**
49
49
  * Based on how things are constructed, the starting field space
50
50
  * can either be another field space or an existing structdef.
51
- * Using a SourceSpace allows a class to accept either one
51
+ * Using a SpaceSeed allows a class to accept either one
52
52
  * and use either version at some future time.
53
53
  */
54
- declare class SourceSpace {
54
+ declare class SpaceSeed {
55
55
  readonly sourceSpec: SourceSpec;
56
56
  private spaceSpec;
57
57
  private asFS?;
@@ -65,7 +65,7 @@ declare class SourceSpace {
65
65
  */
66
66
  export declare class DynamicSpace extends StaticSpace {
67
67
  protected final: model.StructDef | undefined;
68
- protected source: SourceSpace;
68
+ protected source: SpaceSeed;
69
69
  outputFS?: QuerySpace;
70
70
  completions: (() => void)[];
71
71
  private complete;
@@ -86,11 +86,13 @@ export declare class DynamicSpace extends StaticSpace {
86
86
  structDef(): model.StructDef;
87
87
  }
88
88
  /**
89
- * A namespace for Query operations. The have an input and an
90
- * output set of fields. The InputSpace is the QueryOperationSpace
91
- * which is where all expressions are evaluated, and the output
92
- * space is ResultSpace.
89
+ * Unlike a source, which is a refinement of a namespace, a query
90
+ * is creating a new unrelated namespace. The query starts with a
91
+ * source, which it might modify. This set of fields used to resolve
92
+ * expressions in the query is called the "input space". There is a
93
+ * specialized QuerySpace for each type of query operation.
93
94
  *
95
+ * The query output is managed by an instance of ResultSpace.
94
96
  */
95
97
  export declare class QuerySpace extends DynamicSpace {
96
98
  readonly result: ResultSpace;
@@ -167,10 +167,10 @@ function isFieldSpace(x) {
167
167
  /**
168
168
  * Based on how things are constructed, the starting field space
169
169
  * can either be another field space or an existing structdef.
170
- * Using a SourceSpace allows a class to accept either one
170
+ * Using a SpaceSeed allows a class to accept either one
171
171
  * and use either version at some future time.
172
172
  */
173
- class SourceSpace {
173
+ class SpaceSeed {
174
174
  constructor(sourceSpec) {
175
175
  this.sourceSpec = sourceSpec;
176
176
  this.spaceSpec = sourceSpec;
@@ -199,7 +199,7 @@ class SourceSpace {
199
199
  */
200
200
  class DynamicSpace extends StaticSpace {
201
201
  constructor(extending) {
202
- const source = new SourceSpace(extending);
202
+ const source = new SpaceSeed(extending);
203
203
  super((0, lodash_1.cloneDeep)(source.structDef));
204
204
  this.completions = [];
205
205
  this.complete = false;
@@ -365,15 +365,17 @@ class DynamicSpace extends StaticSpace {
365
365
  }
366
366
  exports.DynamicSpace = DynamicSpace;
367
367
  /**
368
- * A namespace for Query operations. The have an input and an
369
- * output set of fields. The InputSpace is the QueryOperationSpace
370
- * which is where all expressions are evaluated, and the output
371
- * space is ResultSpace.
368
+ * Unlike a source, which is a refinement of a namespace, a query
369
+ * is creating a new unrelated namespace. The query starts with a
370
+ * source, which it might modify. This set of fields used to resolve
371
+ * expressions in the query is called the "input space". There is a
372
+ * specialized QuerySpace for each type of query operation.
372
373
  *
374
+ * The query output is managed by an instance of ResultSpace.
373
375
  */
374
376
  class QuerySpace extends DynamicSpace {
375
377
  constructor(input, result) {
376
- const inputSpace = new SourceSpace(input);
378
+ const inputSpace = new SpaceSeed(input);
377
379
  super(inputSpace.structDef);
378
380
  this.result = result;
379
381
  this.extendList = [];