@malloydata/malloy 0.0.248-dev250325232143 → 0.0.248-dev250326010711

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.
@@ -29,7 +29,8 @@ export type FieldReferenceType = 'table' | 'nest source' | 'array[scalar]' | 'ar
29
29
  export declare const dayIndex: number;
30
30
  export declare function inDays(units: string): boolean;
31
31
  export declare function qtz(qi: QueryInfo): string | undefined;
32
- export type OrderByClauseType = 'output_name' | 'ordinal';
32
+ export type OrderByClauseType = 'output_name' | 'ordinal' | 'expression';
33
+ export type OrderByRequest = 'query' | 'turtle' | 'analytical';
33
34
  export declare abstract class Dialect {
34
35
  abstract name: string;
35
36
  abstract defaultNumberType: string;
@@ -121,7 +122,12 @@ export declare abstract class Dialect {
121
122
  sqlSumDistinct(_key: string, _value: string, _funcName: string): string;
122
123
  sqlAggDistinct(_key: string, _values: string[], _func: (valNames: string[]) => string): string;
123
124
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
124
- sqlOrderBy(orderTerms: string[]): string;
125
+ /**
126
+ * MySQL is NULLs first, all other dialects have a way to make NULLs last.
127
+ * isBaseOrdering is a hack to allow the MySQL dialect to partially implement
128
+ * NULLs last, but should go away once MySQL fully implements NULLs last.
129
+ */
130
+ sqlOrderBy(orderTerms: string[], _orderFor?: OrderByRequest): string;
125
131
  sqlTzStr(qi: QueryInfo): string;
126
132
  sqlMakeUnnestKey(key: string, rowKey: string): string;
127
133
  sqlStringAggDistinct(distinctKey: string, valueSQL: string, separatorSQL: string): string;
@@ -179,7 +179,12 @@ class Dialect {
179
179
  }
180
180
  return tableSQL;
181
181
  }
182
- sqlOrderBy(orderTerms) {
182
+ /**
183
+ * MySQL is NULLs first, all other dialects have a way to make NULLs last.
184
+ * isBaseOrdering is a hack to allow the MySQL dialect to partially implement
185
+ * NULLs last, but should go away once MySQL fully implements NULLs last.
186
+ */
187
+ sqlOrderBy(orderTerms, _orderFor) {
183
188
  return `ORDER BY ${orderTerms.join(',')}`;
184
189
  }
185
190
  sqlTzStr(qi) {
@@ -1,5 +1,5 @@
1
1
  import type { Sampling, MeasureTimeExpr, TimeLiteralNode, RegexMatchExpr, TimeDeltaExpr, TimeTruncExpr, TimeExtractExpr, TypecastExpr, LeafAtomicTypeDef, AtomicTypeDef, ArrayLiteralNode, RecordLiteralNode } from '../../model/malloy_types';
2
- import type { DialectFieldList, FieldReferenceType, QueryInfo } from '../dialect';
2
+ import type { DialectFieldList, FieldReferenceType, OrderByClauseType, QueryInfo } from '../dialect';
3
3
  import { Dialect } from '../dialect';
4
4
  import type { DialectFunctionOverloadDef } from '../functions';
5
5
  export declare class MySQLDialect extends Dialect {
@@ -30,6 +30,7 @@ export declare class MySQLDialect extends Dialect {
30
30
  supportsArraysInData: boolean;
31
31
  compoundObjectInSchema: boolean;
32
32
  booleanAsNumbers: boolean;
33
+ orderByClause: OrderByClauseType;
33
34
  malloyTypeToSQLType(malloyType: AtomicTypeDef): string;
34
35
  sqlTypeToMalloyType(sqlType: string): LeafAtomicTypeDef;
35
36
  quoteTablePath(tablePath: string): string;
@@ -65,7 +66,6 @@ export declare class MySQLDialect extends Dialect {
65
66
  sqlMeasureTimeExpr(df: MeasureTimeExpr): string;
66
67
  sqlAggDistinct(_key: string, _values: string[], _func: (valNames: string[]) => string): string;
67
68
  sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
68
- sqlOrderBy(orderTerms: string[]): string;
69
69
  sqlLiteralString(literal: string): string;
70
70
  sqlLiteralRegexp(literal: string): string;
71
71
  getDialectFunctionOverrides(): {
@@ -94,6 +94,7 @@ class MySQLDialect extends dialect_1.Dialect {
94
94
  this.supportsArraysInData = false;
95
95
  this.compoundObjectInSchema = false;
96
96
  this.booleanAsNumbers = true;
97
+ this.orderByClause = 'ordinal';
97
98
  }
98
99
  malloyTypeToSQLType(malloyType) {
99
100
  switch (malloyType.type) {
@@ -400,11 +401,6 @@ class MySQLDialect extends dialect_1.Dialect {
400
401
  }
401
402
  return tableSQL;
402
403
  }
403
- sqlOrderBy(orderTerms) {
404
- return `ORDER BY ${orderTerms
405
- .map(t => `${t.trim().slice(0, t.trim().lastIndexOf(' '))} IS NULL DESC, ${t}`)
406
- .join(',')}`;
407
- }
408
404
  sqlLiteralString(literal) {
409
405
  const noVirgule = literal.replace(/\\/g, '\\\\');
410
406
  return "'" + noVirgule.replace(/'/g, "\\'") + "'";
@@ -1,6 +1,6 @@
1
1
  import type { Sampling, AtomicTypeDef, TimeTruncExpr, TimeExtractExpr, TimeDeltaExpr, TypecastExpr, RegexMatchExpr, TimeLiteralNode, MeasureTimeExpr, LeafAtomicTypeDef, RecordLiteralNode, ArrayLiteralNode } from '../../model/malloy_types';
2
2
  import type { DialectFunctionOverloadDef } from '../functions';
3
- import type { DialectFieldList, QueryInfo } from '../dialect';
3
+ import type { DialectFieldList, OrderByRequest, QueryInfo } from '../dialect';
4
4
  import { Dialect } from '../dialect';
5
5
  export declare class StandardSQLDialect extends Dialect {
6
6
  name: string;
@@ -30,6 +30,7 @@ export declare class StandardSQLDialect extends Dialect {
30
30
  quoteTablePath(tablePath: string): string;
31
31
  sqlGroupSetTable(groupSetCount: number): string;
32
32
  sqlAnyValue(groupSet: number, fieldName: string): string;
33
+ sqlOrderBy(orderTerms: string[], obr?: OrderByRequest): string;
33
34
  sqlAggregateTurtle(groupSet: number, fieldList: DialectFieldList, orderBy: string | undefined, limit: number | undefined): string;
34
35
  sqlAnyValueTurtle(groupSet: number, fieldList: DialectFieldList): string;
35
36
  sqlAnyValueLastTurtle(name: string, groupSet: number, sqlName: string): string;
@@ -110,6 +110,12 @@ class StandardSQLDialect extends dialect_1.Dialect {
110
110
  sqlAnyValue(groupSet, fieldName) {
111
111
  return `ANY_VALUE(CASE WHEN group_set=${groupSet} THEN ${fieldName} END)`;
112
112
  }
113
+ sqlOrderBy(orderTerms, obr) {
114
+ if (obr === 'analytical' || obr === 'turtle') {
115
+ return `ORDER BY ${orderTerms.join(',')}`;
116
+ }
117
+ return `ORDER BY ${orderTerms.map(t => `${t} NULLS LAST`).join(',')}`;
118
+ }
113
119
  // can array agg or any_value a struct...
114
120
  sqlAggregateTurtle(groupSet, fieldList, orderBy, limit) {
115
121
  let tail = '';
@@ -58,9 +58,6 @@ class ExprFilterExpression extends expression_def_1.ExpressionDef {
58
58
  return this.loggedErrorExpr('filter-expression-error', `Filter parse error: ${err.message}`);
59
59
  }
60
60
  }
61
- if (!fParse.parsed) {
62
- return this.loggedErrorExpr('filter-expression-type', 'FJKLD:JDKSL: expression parsed to null');
63
- }
64
61
  const filterMatch = {
65
62
  node: 'filterMatch',
66
63
  dataType: matchExpr.type,
@@ -1,7 +1,7 @@
1
1
  import type { BooleanFilter, FilterExpression, NumberFilter, StringFilter, TemporalFilter } from '@malloydata/malloy-filter';
2
2
  import type { Dialect } from '../dialect';
3
3
  export declare const FilterCompilers: {
4
- compile(t: string, c: FilterExpression, x: string, d: Dialect): string;
4
+ compile(t: string, c: FilterExpression | null, x: string, d: Dialect): string;
5
5
  numberCompile(nc: NumberFilter, x: string, d: Dialect): string;
6
6
  booleanCompile(bc: BooleanFilter, x: string, _d: Dialect): string;
7
7
  stringCompile(sc: StringFilter, x: string, d: Dialect): string;
@@ -37,6 +37,9 @@ function unlike(disLiked, x) {
37
37
  */
38
38
  exports.FilterCompilers = {
39
39
  compile(t, c, x, d) {
40
+ if (c === null) {
41
+ return 'true';
42
+ }
40
43
  if (t === 'string' && (0, malloy_filter_1.isStringFilter)(c)) {
41
44
  return exports.FilterCompilers.stringCompile(c, x, d);
42
45
  }
@@ -677,7 +677,7 @@ class QueryField extends QueryNode {
677
677
  }
678
678
  }
679
679
  if (obSQL.length > 0) {
680
- orderBy = ' ' + this.parent.dialect.sqlOrderBy(obSQL);
680
+ orderBy = ' ' + this.parent.dialect.sqlOrderBy(obSQL, 'analytical');
681
681
  }
682
682
  }
683
683
  let between = '';
@@ -889,7 +889,7 @@ class QueryField extends QueryNode {
889
889
  expr.dataType === 'date' ||
890
890
  expr.dataType === 'timestamp' ||
891
891
  expr.dataType === 'boolean') {
892
- if ((0, malloy_filter_1.isFilterExpression)(expr.filter)) {
892
+ if (expr.filter === null || (0, malloy_filter_1.isFilterExpression)(expr.filter)) {
893
893
  return filter_compilers_1.FilterCompilers.compile(expr.dataType, expr.filter, expr.e.sql || '', this.parent.dialect);
894
894
  }
895
895
  }
@@ -2249,6 +2249,10 @@ class QueryQuery extends QueryField {
2249
2249
  else if (this.parent.dialect.orderByClause === 'output_name') {
2250
2250
  o.push(`${this.parent.dialect.sqlMaybeQuoteIdentifier(f.field)} ${f.dir || 'ASC'}`);
2251
2251
  }
2252
+ else if (this.parent.dialect.orderByClause === 'expression') {
2253
+ const fieldExpr = fi.getSQL();
2254
+ o.push(`${fieldExpr} ${f.dir || 'ASC'}`);
2255
+ }
2252
2256
  }
2253
2257
  else {
2254
2258
  throw new Error(`Unknown field in ORDER BY ${f.field}`);
@@ -2262,10 +2266,15 @@ class QueryQuery extends QueryField {
2262
2266
  const orderingField = resultStruct.getFieldByNumber(f.field);
2263
2267
  o.push(`${this.parent.dialect.sqlMaybeQuoteIdentifier(orderingField.name)} ${f.dir || 'ASC'}`);
2264
2268
  }
2269
+ else if (this.parent.dialect.orderByClause === 'expression') {
2270
+ const orderingField = resultStruct.getFieldByNumber(f.field);
2271
+ const fieldExpr = orderingField.fif.getSQL();
2272
+ o.push(`${fieldExpr} ${f.dir || 'ASC'}`);
2273
+ }
2265
2274
  }
2266
2275
  }
2267
2276
  if (o.length > 0) {
2268
- s = this.parent.dialect.sqlOrderBy(o) + '\n';
2277
+ s = this.parent.dialect.sqlOrderBy(o, 'query') + '\n';
2269
2278
  }
2270
2279
  return s;
2271
2280
  }
@@ -2689,7 +2698,7 @@ class QueryQuery extends QueryField {
2689
2698
  }
2690
2699
  }
2691
2700
  if (obSQL.length > 0) {
2692
- orderBy = ' ' + this.parent.dialect.sqlOrderBy(obSQL);
2701
+ orderBy = ' ' + this.parent.dialect.sqlOrderBy(obSQL, 'turtle');
2693
2702
  }
2694
2703
  const dialectFieldList = this.buildDialectFieldList(resultStruct);
2695
2704
  let resultType;
@@ -181,7 +181,7 @@ export interface FilterMatchExpr extends ExprE {
181
181
  notMatch?: true;
182
182
  filter: {
183
183
  operator: string;
184
- };
184
+ } | null;
185
185
  }
186
186
  export interface TimeLiteralNode extends ExprLeaf {
187
187
  node: 'timeLiteral';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.248-dev250325232143",
3
+ "version": "0.0.248-dev250326010711",
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.248-dev250325232143",
45
- "@malloydata/malloy-interfaces": "^0.0.248-dev250325232143",
46
- "@malloydata/malloy-tag": "^0.0.248-dev250325232143",
44
+ "@malloydata/malloy-filter": "^0.0.248-dev250326010711",
45
+ "@malloydata/malloy-interfaces": "^0.0.248-dev250326010711",
46
+ "@malloydata/malloy-tag": "^0.0.248-dev250326010711",
47
47
  "antlr4ts": "^0.5.0-alpha.4",
48
48
  "assert": "^2.0.0",
49
49
  "jest-diff": "^29.6.2",