@malloydata/malloy 0.0.223-dev241213043533 → 0.0.223-dev241216191808

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.
@@ -7,11 +7,27 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.DUCKDB_DIALECT_FUNCTIONS = void 0;
10
+ const list_extract = {
11
+ takes: { 'value': { array: { generic: 'T' } }, 'index': 'number' },
12
+ generic: { 'T': ['any'] },
13
+ returns: { generic: 'T' },
14
+ impl: { sql: 'list_extract(${value}, ${index})' },
15
+ };
10
16
  const dayname = {
11
17
  takes: { 'date_value': ['date', 'timestamp'] },
12
18
  returns: 'string',
13
19
  impl: { function: 'DAYNAME' },
14
20
  };
21
+ const date_part = {
22
+ takes: { 'part': 'string', 'interval': { sql_native: 'interval' } },
23
+ returns: 'number',
24
+ impl: { function: 'DATE_PART' },
25
+ };
26
+ const to_seconds = {
27
+ takes: { 'seconds': 'number' },
28
+ returns: { sql_native: 'interval' },
29
+ impl: { function: 'TO_SECONDS' },
30
+ };
15
31
  const to_timestamp = {
16
32
  takes: { 'epoch_seconds': 'number' },
17
33
  returns: 'timestamp',
@@ -65,10 +81,13 @@ const string_agg_distinct = {
65
81
  },
66
82
  };
67
83
  exports.DUCKDB_DIALECT_FUNCTIONS = {
84
+ list_extract,
68
85
  count_approx,
69
86
  dayname,
70
87
  to_timestamp,
71
88
  string_agg,
72
89
  string_agg_distinct,
90
+ to_seconds,
91
+ date_part,
73
92
  };
74
93
  //# sourceMappingURL=dialect_functions.js.map
@@ -54,7 +54,7 @@ const chr = {
54
54
  impl: { sql: "CASE WHEN ${value} = 0 THEN '' ELSE CHR(${value}) END" },
55
55
  };
56
56
  const coalesce = {
57
- generic: ['T', ['string', 'number', 'timestamp', 'date', 'json']],
57
+ generic: { 'T': ['string', 'number', 'timestamp', 'date', 'json'] },
58
58
  takes: { 'value': { variadic: { generic: 'T' } } },
59
59
  returns: { generic: 'T' },
60
60
  impl: { function: 'COALESCE' },
@@ -101,13 +101,13 @@ const floor = {
101
101
  impl: { function: 'FLOOR' },
102
102
  };
103
103
  const greatest = {
104
- generic: ['T', ['string', 'number', 'timestamp', 'date', 'json']],
104
+ generic: { 'T': ['string', 'number', 'timestamp', 'date', 'json'] },
105
105
  takes: { 'values': { variadic: { generic: 'T' } } },
106
106
  returns: { generic: 'T' },
107
107
  impl: { function: 'GREATEST' },
108
108
  };
109
109
  const ifnull = {
110
- generic: ['T', ['string', 'number', 'timestamp', 'date', 'json']],
110
+ generic: { 'T': ['string', 'number', 'timestamp', 'date', 'json'] },
111
111
  takes: { 'value': { generic: 'T' }, 'default': { generic: 'T' } },
112
112
  returns: { generic: 'T' },
113
113
  impl: { function: 'IFNULL' },
@@ -162,7 +162,7 @@ const ltrim = {
162
162
  },
163
163
  };
164
164
  const nullif = {
165
- generic: ['T', ['string', 'number', 'timestamp', 'date', 'json']],
165
+ generic: { 'T': ['string', 'number', 'timestamp', 'date', 'json'] },
166
166
  takes: { 'value1': { generic: 'T' }, 'value2': { generic: 'T' } },
167
167
  returns: { generic: 'T' },
168
168
  impl: { function: 'NULLIF' },
@@ -331,7 +331,7 @@ const stddev = {
331
331
  // Analytic functions
332
332
  const avg_moving = {
333
333
  'preceding': {
334
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
334
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
335
335
  takes: {
336
336
  'value': { measure: { generic: 'T' } },
337
337
  'preceding': { literal: 'number' },
@@ -344,7 +344,7 @@ const avg_moving = {
344
344
  },
345
345
  },
346
346
  'following': {
347
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
347
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
348
348
  takes: {
349
349
  'value': { measure: { generic: 'T' } },
350
350
  'preceding': { literal: 'number' },
@@ -359,7 +359,7 @@ const avg_moving = {
359
359
  },
360
360
  };
361
361
  const first_value = {
362
- generic: ['T', ['string', 'number', 'timestamp', 'date', 'json']],
362
+ generic: { 'T': ['string', 'number', 'timestamp', 'date', 'json'] },
363
363
  takes: { 'value': { measure: { generic: 'T' } } },
364
364
  returns: { calculation: { generic: 'T' } },
365
365
  impl: { function: 'FIRST_VALUE', needsWindowOrderBy: true },
@@ -374,7 +374,7 @@ const LAG_TYPES = [
374
374
  ];
375
375
  const lag = {
376
376
  'bare': {
377
- generic: ['T', LAG_TYPES],
377
+ generic: { 'T': LAG_TYPES },
378
378
  takes: {
379
379
  'value': { measure: { generic: 'T' } },
380
380
  },
@@ -382,7 +382,7 @@ const lag = {
382
382
  impl: { function: 'LAG', needsWindowOrderBy: true },
383
383
  },
384
384
  'with_offset': {
385
- generic: ['T', LAG_TYPES],
385
+ generic: { 'T': LAG_TYPES },
386
386
  takes: {
387
387
  'value': { measure: { generic: 'T' } },
388
388
  'offset': { literal: 'number' },
@@ -391,7 +391,7 @@ const lag = {
391
391
  impl: { function: 'LAG', needsWindowOrderBy: true },
392
392
  },
393
393
  'with_default': {
394
- generic: ['T', LAG_TYPES],
394
+ generic: { 'T': LAG_TYPES },
395
395
  takes: {
396
396
  'value': { measure: { generic: 'T' } },
397
397
  'offset': { literal: 'number' },
@@ -402,7 +402,7 @@ const lag = {
402
402
  },
403
403
  };
404
404
  const last_value = {
405
- generic: ['T', ['string', 'number', 'timestamp', 'date', 'json']],
405
+ generic: { 'T': ['string', 'number', 'timestamp', 'date', 'json'] },
406
406
  takes: { 'value': { measure: { generic: 'T' } } },
407
407
  returns: { calculation: { generic: 'T' } },
408
408
  impl: {
@@ -426,25 +426,25 @@ const lead = {
426
426
  },
427
427
  };
428
428
  const max_cumulative = {
429
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
429
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
430
430
  takes: { 'value': { measure: { generic: 'T' } } },
431
431
  returns: { calculation: { generic: 'T' } },
432
432
  impl: { function: 'MAX', needsWindowOrderBy: true },
433
433
  };
434
434
  const max_window = {
435
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
435
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
436
436
  takes: { 'value': { measure: { generic: 'T' } } },
437
437
  returns: { calculation: { generic: 'T' } },
438
438
  impl: { function: 'MAX', needsWindowOrderBy: false },
439
439
  };
440
440
  const min_cumulative = {
441
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
441
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
442
442
  takes: { 'value': { measure: { generic: 'T' } } },
443
443
  returns: { calculation: { generic: 'T' } },
444
444
  impl: { function: 'MIN', needsWindowOrderBy: true },
445
445
  };
446
446
  const min_window = {
447
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
447
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
448
448
  takes: { 'value': { measure: { generic: 'T' } } },
449
449
  returns: { calculation: { generic: 'T' } },
450
450
  impl: { function: 'MIN', needsWindowOrderBy: false },
@@ -461,14 +461,14 @@ const row_number = {
461
461
  impl: { function: 'ROW_NUMBER', needsWindowOrderBy: true },
462
462
  };
463
463
  const sum_cumulative = {
464
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
464
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
465
465
  takes: { 'value': { measure: { generic: 'T' } } },
466
466
  returns: { calculation: { generic: 'T' } },
467
467
  impl: { function: 'SUM', needsWindowOrderBy: true },
468
468
  };
469
469
  const sum_moving = {
470
470
  'preceding': {
471
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
471
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
472
472
  takes: {
473
473
  'value': { measure: { generic: 'T' } },
474
474
  'preceding': { literal: 'number' },
@@ -481,7 +481,7 @@ const sum_moving = {
481
481
  },
482
482
  },
483
483
  'following': {
484
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
484
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
485
485
  takes: {
486
486
  'value': { measure: { generic: 'T' } },
487
487
  'preceding': { literal: 'number' },
@@ -496,7 +496,7 @@ const sum_moving = {
496
496
  },
497
497
  };
498
498
  const sum_window = {
499
- generic: ['T', ['string', 'number', 'timestamp', 'date']],
499
+ generic: { 'T': ['string', 'number', 'timestamp', 'date'] },
500
500
  takes: { 'value': { measure: { generic: 'T' } } },
501
501
  returns: { calculation: { generic: 'T' } },
502
502
  impl: { function: 'SUM', needsWindowOrderBy: false },
@@ -1,8 +1,12 @@
1
- import { FunctionParameterDef, TypeDesc, Expr, FunctionParamTypeDesc, LeafExpressionType } from '../../model/malloy_types';
1
+ import { FunctionParameterDef, TypeDesc, Expr, FunctionParamTypeDesc, LeafExpressionType, FunctionReturnTypeDesc, FunctionParameterTypeDef, ExpressionType, EvalSpace, FunctionGenericTypeDef } from '../../model/malloy_types';
2
2
  import { SQLExprElement } from '../../model/utils';
3
3
  export interface DialectFunctionOverloadDef {
4
- returnType: TypeDesc;
4
+ returnType: FunctionReturnTypeDesc;
5
5
  params: FunctionParameterDef[];
6
+ genericTypes?: {
7
+ name: string;
8
+ acceptibleTypes: FunctionGenericTypeDef[];
9
+ }[];
6
10
  e: Expr;
7
11
  needsWindowOrderBy?: boolean;
8
12
  isSymmetric?: boolean;
@@ -17,9 +21,15 @@ export interface DialectFunctionOverloadDef {
17
21
  export declare function arg(name: string): Expr;
18
22
  export declare function spread(e: Expr, prefix?: string | undefined, suffix?: string | undefined): Expr;
19
23
  export declare function sql(strings: TemplateStringsArray, ...subExprs: SQLExprElement[]): Expr;
20
- export declare function constant(type: FunctionParamTypeDesc): FunctionParamTypeDesc;
21
- export declare function output(type: FunctionParamTypeDesc): FunctionParamTypeDesc;
22
- export declare function literal(type: FunctionParamTypeDesc): FunctionParamTypeDesc;
24
+ export declare function constant<T extends {
25
+ expressionType: ExpressionType | undefined;
26
+ }>(type: T): T & TypeDescExtras;
27
+ export declare function output<T extends {
28
+ expressionType: ExpressionType | undefined;
29
+ }>(type: T): T & TypeDescExtras;
30
+ export declare function literal<T extends {
31
+ expressionType: ExpressionType | undefined;
32
+ }>(type: T): T & TypeDescExtras;
23
33
  export declare function variadicParam(name: string, ...allowedTypes: FunctionParamTypeDesc[]): FunctionParameterDef;
24
34
  /**
25
35
  * Prefer `makeParam` for future function definitions
@@ -29,14 +39,18 @@ export declare function makeParam(name: string, ...allowedTypes: FunctionParamTy
29
39
  param: FunctionParameterDef;
30
40
  arg: Expr;
31
41
  };
32
- export declare function maxScalar(type: LeafExpressionType): FunctionParamTypeDesc;
33
- export declare function maxAggregate(type: LeafExpressionType): FunctionParamTypeDesc;
34
- export declare function anyExprType(type: LeafExpressionType): FunctionParamTypeDesc;
35
- export declare function maxUngroupedAggregate(type: LeafExpressionType): FunctionParamTypeDesc;
36
- export declare function maxAnalytic(type: LeafExpressionType): FunctionParamTypeDesc;
37
- export declare function minScalar(type: LeafExpressionType): FunctionParamTypeDesc;
38
- export declare function minAggregate(type: LeafExpressionType): FunctionParamTypeDesc;
39
- export declare function minAnalytic(type: LeafExpressionType): FunctionParamTypeDesc;
42
+ export declare function maxScalar<T>(type: T): T & TypeDescExtras;
43
+ export declare function maxAggregate<T>(type: T): T & TypeDescExtras;
44
+ export declare function anyExprType<T>(type: T): T & TypeDescExtras;
45
+ export declare function maxUngroupedAggregate(type: FunctionParameterTypeDef): FunctionParamTypeDesc;
46
+ type TypeDescExtras = {
47
+ expressionType: ExpressionType | undefined;
48
+ evalSpace: EvalSpace;
49
+ };
50
+ export declare function maxAnalytic<T>(type: T): T & TypeDescExtras;
51
+ export declare function minScalar<T>(type: T): T & TypeDescExtras;
52
+ export declare function minAggregate<T>(type: T): T & TypeDescExtras;
53
+ export declare function minAnalytic<T>(type: T): T & TypeDescExtras;
40
54
  export declare function overload(returnType: TypeDesc, params: FunctionParameterDef[], e: Expr, options?: {
41
55
  needsWindowOrderBy?: boolean;
42
56
  between?: {
@@ -49,40 +63,38 @@ export declare function overload(returnType: TypeDesc, params: FunctionParameter
49
63
  supportsOrderBy?: boolean | 'only_default';
50
64
  }): DialectFunctionOverloadDef;
51
65
  export interface ArrayBlueprint {
52
- array: TypeDescElementBlueprint;
66
+ array: TypeDescElementBlueprintOrNamedGeneric;
53
67
  }
68
+ export type TypeDescElementBlueprintOrNamedGeneric = TypeDescElementBlueprint | NamedGeneric;
54
69
  export interface RecordBlueprint {
55
- record: Record<string, TypeDescElementBlueprint>;
70
+ record: Record<string, TypeDescElementBlueprintOrNamedGeneric>;
71
+ }
72
+ export interface SQLNativeTypeBlueprint {
73
+ sql_native: string;
56
74
  }
57
- export type TypeDescElementBlueprint = LeafExpressionType | ArrayBlueprint | RecordBlueprint;
58
- export type TypeDescBlueprint = TypeDescElementBlueprint | {
75
+ export type LeafPlusType = LeafExpressionType | 'any';
76
+ export type TypeDescElementBlueprint = LeafPlusType | ArrayBlueprint | RecordBlueprint | SQLNativeTypeBlueprint;
77
+ export type NamedGeneric = {
59
78
  generic: string;
79
+ };
80
+ export type TypeDescBlueprint = TypeDescElementBlueprintOrNamedGeneric | {
81
+ literal: TypeDescElementBlueprintOrNamedGeneric;
60
82
  } | {
61
- literal: LeafExpressionType | {
62
- generic: string;
63
- };
64
- } | {
65
- constant: LeafExpressionType | {
66
- generic: string;
67
- };
83
+ constant: TypeDescElementBlueprintOrNamedGeneric;
68
84
  } | {
69
- dimension: LeafExpressionType | {
70
- generic: string;
71
- };
85
+ dimension: TypeDescElementBlueprintOrNamedGeneric;
72
86
  } | {
73
- measure: LeafExpressionType | {
74
- generic: string;
75
- };
87
+ measure: TypeDescElementBlueprintOrNamedGeneric;
76
88
  } | {
77
- calculation: LeafExpressionType | {
78
- generic: string;
79
- };
89
+ calculation: TypeDescElementBlueprintOrNamedGeneric;
80
90
  };
81
91
  type ParamTypeBlueprint = TypeDescBlueprint | TypeDescBlueprint[] | {
82
92
  variadic: TypeDescBlueprint | TypeDescBlueprint[];
83
93
  };
84
94
  export interface SignatureBlueprint {
85
- generic?: [string, LeafExpressionType[]];
95
+ generic?: {
96
+ [name: string]: TypeDescElementBlueprintOrNamedGeneric[];
97
+ };
86
98
  takes: {
87
99
  [name: string]: ParamTypeBlueprint;
88
100
  };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  /*
3
3
  * Copyright 2023 Google LLC
4
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
5
  *
5
6
  * Permission is hereby granted, free of charge, to any person obtaining
6
7
  * a copy of this software and associated documentation files
@@ -23,7 +24,6 @@
23
24
  */
24
25
  Object.defineProperty(exports, "__esModule", { value: true });
25
26
  exports.expandOverrideMapFromBase = exports.expandBlueprintMap = exports.overload = exports.minAnalytic = exports.minAggregate = exports.minScalar = exports.maxAnalytic = exports.maxUngroupedAggregate = exports.anyExprType = exports.maxAggregate = exports.maxScalar = exports.makeParam = exports.param = exports.variadicParam = exports.literal = exports.output = exports.constant = exports.sql = exports.spread = exports.arg = void 0;
26
- const composite_source_utils_1 = require("../../model/composite_source_utils");
27
27
  const malloy_types_1 = require("../../model/malloy_types");
28
28
  function arg(name) {
29
29
  return { node: 'function_parameter', name };
@@ -106,39 +106,35 @@ function makeParam(name, ...allowedTypes) {
106
106
  }
107
107
  exports.makeParam = makeParam;
108
108
  function maxScalar(type) {
109
- return { type, expressionType: 'scalar', evalSpace: 'input' };
109
+ return { ...type, expressionType: 'scalar', evalSpace: 'input' };
110
110
  }
111
111
  exports.maxScalar = maxScalar;
112
112
  function maxAggregate(type) {
113
- return { type, expressionType: 'aggregate', evalSpace: 'input' };
113
+ return { ...type, expressionType: 'aggregate', evalSpace: 'input' };
114
114
  }
115
115
  exports.maxAggregate = maxAggregate;
116
116
  function anyExprType(type) {
117
- return { type, expressionType: undefined, evalSpace: 'input' };
117
+ return { ...type, expressionType: undefined, evalSpace: 'input' };
118
118
  }
119
119
  exports.anyExprType = anyExprType;
120
- function anyExprTypeBP(type, generic) {
121
- const typeDesc = expandReturnTypeBlueprint(type, generic);
122
- return { ...typeDesc, expressionType: undefined, evalSpace: 'input' };
123
- }
124
120
  function maxUngroupedAggregate(type) {
125
- return { type, expressionType: 'ungrouped_aggregate', evalSpace: 'input' };
121
+ return { ...type, expressionType: 'ungrouped_aggregate', evalSpace: 'input' };
126
122
  }
127
123
  exports.maxUngroupedAggregate = maxUngroupedAggregate;
128
124
  function maxAnalytic(type) {
129
- return { type, expressionType: 'aggregate_analytic', evalSpace: 'input' };
125
+ return { ...type, expressionType: 'aggregate_analytic', evalSpace: 'input' };
130
126
  }
131
127
  exports.maxAnalytic = maxAnalytic;
132
128
  function minScalar(type) {
133
- return { type, expressionType: 'scalar', evalSpace: 'input' };
129
+ return { ...type, expressionType: 'scalar', evalSpace: 'input' };
134
130
  }
135
131
  exports.minScalar = minScalar;
136
132
  function minAggregate(type) {
137
- return { type, expressionType: 'aggregate', evalSpace: 'input' };
133
+ return { ...type, expressionType: 'aggregate', evalSpace: 'input' };
138
134
  }
139
135
  exports.minAggregate = minAggregate;
140
136
  function minAnalytic(type) {
141
- return { type, expressionType: 'scalar_analytic', evalSpace: 'input' };
137
+ return { ...type, expressionType: 'scalar_analytic', evalSpace: 'input' };
142
138
  }
143
139
  exports.minAnalytic = minAnalytic;
144
140
  function overload(returnType, params, e, options) {
@@ -155,86 +151,89 @@ function overload(returnType, params, e, options) {
155
151
  };
156
152
  }
157
153
  exports.overload = overload;
158
- function removeGeneric(type, generic) {
159
- if (typeof type === 'string') {
160
- return type;
161
- }
162
- if (type.generic !== (generic === null || generic === void 0 ? void 0 : generic.name)) {
163
- throw new Error(`Cannot expand generic name ${type.generic}`);
154
+ function expandTypeDescElementBlueprint(blueprint, allowAny = true, allowGenerics = true) {
155
+ if (!allowAny && blueprint === 'any') {
156
+ throw new Error('Return type cannot include any');
164
157
  }
165
- return generic.type;
166
- }
167
- function expandReturnTypeBlueprint(blueprint, generic) {
168
- var _a;
169
- let base;
170
158
  if (typeof blueprint === 'string') {
171
- base = minScalar(blueprint);
159
+ return { type: blueprint };
172
160
  }
173
161
  else if ('array' in blueprint) {
174
- const innerType = expandReturnTypeBlueprint(blueprint.array, generic);
175
- const { expressionType, evalSpace } = innerType;
176
- if (malloy_types_1.TD.isAtomic(innerType)) {
177
- if (innerType.type !== 'record') {
178
- base = {
179
- type: 'array',
180
- elementTypeDef: innerType,
181
- expressionType,
182
- evalSpace,
183
- };
184
- }
185
- else {
186
- base = {
187
- type: 'array',
188
- elementTypeDef: { type: 'record_element' },
189
- fields: innerType.fields,
190
- expressionType,
191
- evalSpace,
192
- };
193
- }
194
- }
195
- else {
196
- // mtoy todo fix by doing "exapndElementBlueprint" ...
197
- throw new Error(`TypeDescElementBlueprint should never allow ${blueprint.array}`);
162
+ const innerType = allowAny
163
+ ? expandTypeDescElementBlueprint(blueprint.array, true)
164
+ : expandTypeDescElementBlueprint(blueprint.array, false);
165
+ if (innerType.type === 'record') {
166
+ return {
167
+ type: 'array',
168
+ elementTypeDef: { type: 'record_element' },
169
+ fields: innerType.fields,
170
+ };
198
171
  }
172
+ return {
173
+ type: 'array',
174
+ elementTypeDef: innerType,
175
+ };
199
176
  }
200
177
  else if ('record' in blueprint) {
201
178
  const fields = [];
202
179
  for (const [fieldName, fieldBlueprint] of Object.entries(blueprint.record)) {
203
- const fieldDesc = expandReturnTypeBlueprint(fieldBlueprint, generic);
180
+ const fieldDesc = allowAny
181
+ ? expandTypeDescElementBlueprint(fieldBlueprint, true)
182
+ : expandTypeDescElementBlueprint(fieldBlueprint, false);
204
183
  if (malloy_types_1.TD.isAtomic(fieldDesc)) {
205
184
  fields.push((0, malloy_types_1.mkFieldDef)(fieldDesc, fieldName));
206
185
  }
207
186
  }
208
- base = {
187
+ return {
209
188
  type: 'record',
210
189
  fields,
211
- evalSpace: 'input',
212
- expressionType: 'scalar',
213
190
  };
214
191
  }
215
192
  else if ('generic' in blueprint) {
216
- base = minScalar(removeGeneric(blueprint, generic));
193
+ if (!allowGenerics) {
194
+ throw new Error('Cannot use generic');
195
+ }
196
+ return { type: 'generic', generic: blueprint.generic };
197
+ }
198
+ else if ('sql_native' in blueprint) {
199
+ return { type: 'sql native', rawType: blueprint.sql_native };
200
+ }
201
+ throw new Error('Cannot figure out type');
202
+ }
203
+ function expandReturnTypeBlueprint(blueprint) {
204
+ if (blueprint === 'any') {
205
+ throw new Error('Cannot return any type');
206
+ }
207
+ if (typeof blueprint === 'string') {
208
+ return minScalar({ type: blueprint });
209
+ }
210
+ else if ('array' in blueprint) {
211
+ return anyExprType(expandTypeDescElementBlueprint(blueprint, false));
212
+ }
213
+ else if ('record' in blueprint) {
214
+ return anyExprType(expandTypeDescElementBlueprint(blueprint, false));
215
+ }
216
+ else if ('generic' in blueprint) {
217
+ return minScalar(expandTypeDescElementBlueprint(blueprint, false));
217
218
  }
218
219
  else if ('literal' in blueprint) {
219
- base = literal(minScalar(removeGeneric(blueprint.literal, generic)));
220
+ return literal(minScalar(expandTypeDescElementBlueprint(blueprint.literal, false)));
220
221
  }
221
222
  else if ('constant' in blueprint) {
222
- base = constant(minScalar(removeGeneric(blueprint.constant, generic)));
223
+ return constant(minScalar(expandTypeDescElementBlueprint(blueprint.constant, false)));
223
224
  }
224
225
  else if ('dimension' in blueprint) {
225
- base = minScalar(removeGeneric(blueprint.dimension, generic));
226
+ return minScalar(expandTypeDescElementBlueprint(blueprint.dimension, false));
226
227
  }
227
228
  else if ('measure' in blueprint) {
228
- base = minAggregate(removeGeneric(blueprint.measure, generic));
229
+ return minAggregate(expandTypeDescElementBlueprint(blueprint.measure, false));
230
+ }
231
+ else if ('sql_native' in blueprint) {
232
+ return anyExprType({ type: 'sql native', rawType: blueprint.sql_native });
229
233
  }
230
234
  else {
231
- base = minAnalytic(removeGeneric(blueprint.calculation, generic));
235
+ return minAnalytic(expandTypeDescElementBlueprint(blueprint.calculation, false));
232
236
  }
233
- return {
234
- ...base,
235
- compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
236
- expressionType: (_a = base.expressionType) !== null && _a !== void 0 ? _a : 'scalar',
237
- };
238
237
  }
239
238
  function isTypeDescBlueprint(blueprint) {
240
239
  return (typeof blueprint === 'string' ||
@@ -245,7 +244,8 @@ function isTypeDescBlueprint(blueprint) {
245
244
  'constant' in blueprint ||
246
245
  'dimension' in blueprint ||
247
246
  'measure' in blueprint ||
248
- 'calculation' in blueprint);
247
+ 'calculation' in blueprint ||
248
+ 'sql_native' in blueprint);
249
249
  }
250
250
  function extractParamTypeBlueprints(blueprint) {
251
251
  if (isTypeDescBlueprint(blueprint)) {
@@ -261,51 +261,54 @@ function extractParamTypeBlueprints(blueprint) {
261
261
  return blueprint.variadic;
262
262
  }
263
263
  }
264
- function expandParamTypeBlueprint(blueprint, generic) {
264
+ function expandParamTypeBlueprint(blueprint) {
265
265
  if (typeof blueprint === 'string') {
266
- return anyExprType(blueprint);
266
+ return anyExprType({ type: blueprint });
267
267
  }
268
268
  else if ('generic' in blueprint) {
269
- return anyExprType(removeGeneric(blueprint, generic));
269
+ return anyExprType(expandTypeDescElementBlueprint(blueprint));
270
270
  }
271
271
  else if ('literal' in blueprint) {
272
- return literal(maxScalar(removeGeneric(blueprint.literal, generic)));
272
+ return literal(maxScalar(expandTypeDescElementBlueprint(blueprint.literal)));
273
273
  }
274
274
  else if ('constant' in blueprint) {
275
- return constant(maxScalar(removeGeneric(blueprint.constant, generic)));
275
+ return constant(maxScalar(expandTypeDescElementBlueprint(blueprint.constant)));
276
276
  }
277
277
  else if ('dimension' in blueprint) {
278
- return maxScalar(removeGeneric(blueprint.dimension, generic));
278
+ return maxScalar(expandTypeDescElementBlueprint(blueprint.dimension));
279
279
  }
280
280
  else if ('measure' in blueprint) {
281
- return maxAggregate(removeGeneric(blueprint.measure, generic));
281
+ return maxAggregate(expandTypeDescElementBlueprint(blueprint.measure));
282
282
  }
283
283
  else if ('array' in blueprint) {
284
- return anyExprTypeBP(blueprint, generic);
284
+ return anyExprType(expandTypeDescElementBlueprint(blueprint, false));
285
285
  }
286
286
  else if ('record' in blueprint) {
287
- return anyExprTypeBP(blueprint, generic);
287
+ return anyExprType(expandTypeDescElementBlueprint(blueprint, false));
288
+ }
289
+ else if ('sql_native' in blueprint) {
290
+ return anyExprType({ type: 'sql native', rawType: blueprint.sql_native });
288
291
  }
289
292
  else {
290
- return maxAnalytic(removeGeneric(blueprint.calculation, generic));
293
+ return maxAnalytic(expandTypeDescElementBlueprint(blueprint.calculation));
291
294
  }
292
295
  }
293
- function expandParamTypeBlueprints(blueprints, generic) {
294
- return blueprints.map(blueprint => expandParamTypeBlueprint(blueprint, generic));
296
+ function expandParamTypeBlueprints(blueprints) {
297
+ return blueprints.map(blueprint => expandParamTypeBlueprint(blueprint));
295
298
  }
296
299
  function isVariadicParamBlueprint(blueprint) {
297
300
  return typeof blueprint !== 'string' && 'variadic' in blueprint;
298
301
  }
299
- function expandParamBlueprint(name, blueprint, generic) {
302
+ function expandParamBlueprint(name, blueprint) {
300
303
  return {
301
304
  name,
302
- allowedTypes: expandParamTypeBlueprints(extractParamTypeBlueprints(blueprint), generic),
305
+ allowedTypes: expandParamTypeBlueprints(extractParamTypeBlueprints(blueprint)),
303
306
  isVariadic: isVariadicParamBlueprint(blueprint),
304
307
  };
305
308
  }
306
- function expandParamsBlueprints(blueprints, generic) {
309
+ function expandParamsBlueprints(blueprints) {
307
310
  const paramsArray = Object.entries(blueprints);
308
- return paramsArray.map(blueprint => expandParamBlueprint(blueprint[0], blueprint[1], generic));
311
+ return paramsArray.map(blueprint => expandParamBlueprint(blueprint[0], blueprint[1]));
309
312
  }
310
313
  function expandBlueprintSqlInterpolation(sql) {
311
314
  const src = [];
@@ -393,23 +396,25 @@ function expandImplBlueprint(blueprint) {
393
396
  defaultOrderByArgIndex: blueprint.impl.defaultOrderByArgIndex,
394
397
  };
395
398
  }
396
- function expandOneBlueprint(blueprint, generic) {
399
+ function expandGenericDefinitions(blueprint) {
400
+ if (blueprint === undefined)
401
+ return undefined;
402
+ return Object.entries(blueprint).map(([name, acceptibleTypes]) => ({
403
+ name: name,
404
+ acceptibleTypes: acceptibleTypes.map(t => expandTypeDescElementBlueprint(t, true, false)),
405
+ }));
406
+ }
407
+ function expandBlueprint(blueprint) {
397
408
  return {
398
- returnType: expandReturnTypeBlueprint(blueprint.returns, generic),
399
- params: expandParamsBlueprints(blueprint.takes, generic),
409
+ returnType: expandReturnTypeBlueprint(blueprint.returns),
410
+ params: expandParamsBlueprints(blueprint.takes),
400
411
  isSymmetric: blueprint.isSymmetric,
401
412
  supportsOrderBy: blueprint.supportsOrderBy,
402
413
  supportsLimit: blueprint.supportsLimit,
414
+ genericTypes: expandGenericDefinitions(blueprint.generic),
403
415
  ...expandImplBlueprint(blueprint),
404
416
  };
405
417
  }
406
- function expandBlueprint(blueprint) {
407
- if (blueprint.generic !== undefined) {
408
- const name = blueprint.generic[0];
409
- return blueprint.generic[1].map(type => expandOneBlueprint(blueprint, { name, type }));
410
- }
411
- return [expandOneBlueprint(blueprint)];
412
- }
413
418
  function isDefinitionBlueprint(blueprint) {
414
419
  return 'takes' in blueprint && 'returns' in blueprint && 'impl' in blueprint;
415
420
  }
@@ -418,7 +423,7 @@ function isImplementationBlueprint(blueprint) {
418
423
  }
419
424
  function expandOverloadedBlueprint(blueprint) {
420
425
  if (isDefinitionBlueprint(blueprint)) {
421
- return expandBlueprint(blueprint);
426
+ return [expandBlueprint(blueprint)];
422
427
  }
423
428
  else {
424
429
  return Object.values(blueprint).flatMap(overload => expandBlueprint(overload));
@@ -433,7 +438,7 @@ function expandBlueprintMap(blueprints) {
433
438
  }
434
439
  exports.expandBlueprintMap = expandBlueprintMap;
435
440
  function expandImplementationBlueprint(base, impl) {
436
- return expandBlueprint({ ...base, impl });
441
+ return [expandBlueprint({ ...base, impl })];
437
442
  }
438
443
  function expandOverloadedOverrideBlueprint(name, base, blueprint) {
439
444
  if (isImplementationBlueprint(blueprint)) {
@@ -20,7 +20,7 @@ const approx_percentile = {
20
20
  },
21
21
  };
22
22
  const arbitrary = {
23
- generic: ['T', ['string', 'number', 'date', 'timestamp', 'boolean', 'json']],
23
+ generic: { 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'] },
24
24
  takes: { 'value': { dimension: { generic: 'T' } } },
25
25
  returns: { measure: { generic: 'T' } },
26
26
  impl: { function: 'ARBITRARY' },
@@ -64,7 +64,7 @@ const count_approx = {
64
64
  isSymmetric: true,
65
65
  };
66
66
  const max_by = {
67
- generic: ['T', ['string', 'number', 'date', 'timestamp', 'boolean', 'json']],
67
+ generic: { 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'] },
68
68
  takes: {
69
69
  'value': { dimension: { generic: 'T' } },
70
70
  'order_by_val': { dimension: 'any' },
@@ -74,7 +74,7 @@ const max_by = {
74
74
  isSymmetric: true,
75
75
  };
76
76
  const min_by = {
77
- generic: ['T', ['string', 'number', 'date', 'timestamp', 'boolean', 'json']],
77
+ generic: { 'T': ['string', 'number', 'date', 'timestamp', 'boolean', 'json'] },
78
78
  takes: {
79
79
  'value': { dimension: { generic: 'T' } },
80
80
  'order_by_val': { dimension: 'any' },
@@ -101,7 +101,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
101
101
  return { found: func, error: undefined };
102
102
  }
103
103
  getPropsExpression(fs, props) {
104
- var _a, _b, _c;
104
+ var _a, _b, _c, _d;
105
105
  const argExprsWithoutImplicit = this.args.map(arg => arg.getExpression(fs));
106
106
  if (this.isRaw) {
107
107
  const funcCall = [`${this.name}(`];
@@ -167,7 +167,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
167
167
  .map(e => e.type)
168
168
  .join(', ')})`);
169
169
  }
170
- const { overload, expressionTypeErrors, evalSpaceErrors, nullabilityErrors } = result;
170
+ const { overload, expressionTypeErrors, evalSpaceErrors, nullabilityErrors, returnType, } = result;
171
171
  // Report errors for expression type mismatch
172
172
  for (const error of expressionTypeErrors) {
173
173
  const adjustedIndex = error.argIndex - (implicitExpr ? 1 : 0);
@@ -194,9 +194,13 @@ class ExprFunc extends expression_def_1.ExpressionDef {
194
194
  const arg = this.args[adjustedIndex];
195
195
  arg.logError('literal-null-function-argument', `Parameter ${error.argIndex + 1} ('${error.param.name}') of ${this.name} must not be a literal null`);
196
196
  }
197
+ // Report return type error
198
+ if (result.returnTypeError) {
199
+ this.logError(result.returnTypeError.code, result.returnTypeError.parameters);
200
+ }
197
201
  const type = overload.returnType;
198
202
  const expressionType = (0, malloy_types_1.maxOfExpressionTypes)([
199
- type.expressionType,
203
+ (_d = type.expressionType) !== null && _d !== void 0 ? _d : 'scalar',
200
204
  ...argExprs.map(e => e.expressionType),
201
205
  ]);
202
206
  if (!(0, malloy_types_1.expressionIsAggregate)(overload.returnType.expressionType) &&
@@ -316,9 +320,6 @@ class ExprFunc extends expression_def_1.ExpressionDef {
316
320
  funcCall = (0, utils_1.composeSQLExpr)(expr);
317
321
  }
318
322
  }
319
- if (type.type === 'any') {
320
- return this.loggedErrorExpr('function-returns-any', `Invalid return type ${type.type} for function '${this.name}'`);
321
- }
322
323
  const maxEvalSpace = (0, malloy_types_1.mergeEvalSpaces)(...argExprs.map(e => e.evalSpace));
323
324
  // If the merged eval space of all args is constant, the result is constant.
324
325
  // If the expression is scalar, then the eval space is that merged eval space.
@@ -333,7 +334,8 @@ class ExprFunc extends expression_def_1.ExpressionDef {
333
334
  // TODO consider if I can use `computedExprValue` here...
334
335
  // seems like the rules for the evalSpace is a bit different from normal though
335
336
  return {
336
- ...TDU.atomicDef(type),
337
+ // TODO need to handle this???
338
+ ...((0, malloy_types_1.isAtomic)(returnType) ? TDU.atomicDef(returnType) : returnType),
337
339
  expressionType,
338
340
  value: funcCall,
339
341
  evalSpace,
@@ -343,7 +345,10 @@ class ExprFunc extends expression_def_1.ExpressionDef {
343
345
  }
344
346
  exports.ExprFunc = ExprFunc;
345
347
  function findOverload(func, args) {
348
+ var _a;
346
349
  for (const overload of func.overloads) {
350
+ // Map from generic name to selected type
351
+ const genericsSelected = new Map();
347
352
  let paramIndex = 0;
348
353
  let ok = true;
349
354
  let matchedVariadic = false;
@@ -358,15 +363,13 @@ function findOverload(func, args) {
358
363
  break;
359
364
  }
360
365
  const argOk = param.allowedTypes.some(paramT => {
366
+ var _a;
361
367
  // Check whether types match (allowing for nullability errors, expression type errors,
362
368
  // eval space errors, and unknown types due to prior errors in args)
363
- const dataTypeMatch = malloy_types_1.TD.eq(paramT, arg) ||
364
- paramT.type === 'any' ||
365
- // TODO We should consider whether `nulls` should always be allowed. It probably
366
- // does not make sense to limit function calls to not allow nulls, since have
367
- // so little control over nullability.
368
- arg.type === 'null' ||
369
- arg.type === 'error';
369
+ const { dataTypeMatch, genericsSet } = isDataTypeMatch(genericsSelected, (_a = overload.genericTypes) !== null && _a !== void 0 ? _a : [], arg, paramT);
370
+ for (const genericSet of genericsSet) {
371
+ genericsSelected.set(genericSet.name, genericSet.type);
372
+ }
370
373
  // Check expression type errors
371
374
  if (paramT.expressionType) {
372
375
  const expressionTypeMatch = (0, malloy_types_1.isExpressionTypeLEQ)(arg.expressionType, paramT.expressionType);
@@ -425,12 +428,16 @@ function findOverload(func, args) {
425
428
  (paramIndex !== args.length || paramIndex !== overload.params.length)) {
426
429
  continue;
427
430
  }
431
+ const resolveReturnType = resolveGenerics(overload.returnType, genericsSelected);
432
+ const returnType = (_a = resolveReturnType.returnType) !== null && _a !== void 0 ? _a : { type: 'number' };
428
433
  if (ok) {
429
434
  return {
430
435
  overload,
431
436
  expressionTypeErrors,
432
437
  evalSpaceErrors,
433
438
  nullabilityErrors,
439
+ returnTypeError: resolveReturnType.error,
440
+ returnType,
434
441
  };
435
442
  }
436
443
  }
@@ -462,4 +469,163 @@ function parseSQLInterpolation(template) {
462
469
  }
463
470
  return parts;
464
471
  }
472
+ function isDataTypeMatch(genericsAlreadySelected, genericTypes, arg, paramT) {
473
+ var _a, _b, _c, _d;
474
+ if (malloy_types_1.TD.eq(paramT, arg) ||
475
+ paramT.type === 'any' ||
476
+ // TODO We should consider whether `nulls` should always be allowed. It probably
477
+ // does not make sense to limit function calls to not allow nulls, since have
478
+ // so little control over nullability.
479
+ (paramT.type !== 'generic' && (arg.type === 'null' || arg.type === 'error'))) {
480
+ return { dataTypeMatch: true, genericsSet: [] };
481
+ }
482
+ if (paramT.type === 'array' && arg.type === 'array') {
483
+ if ((0, malloy_types_1.isScalarArray)(arg)) {
484
+ if (!(0, malloy_types_1.isRepeatedRecordFunctionParam)(paramT)) {
485
+ return isDataTypeMatch(genericsAlreadySelected, genericTypes, arg.elementTypeDef, paramT.elementTypeDef);
486
+ }
487
+ else {
488
+ return { dataTypeMatch: false, genericsSet: [] };
489
+ }
490
+ }
491
+ else if ((0, malloy_types_1.isRepeatedRecordFunctionParam)(paramT)) {
492
+ const fakeParamRecord = {
493
+ type: 'record',
494
+ fields: paramT.fields,
495
+ };
496
+ const fakeArgRecord = {
497
+ type: 'record',
498
+ fields: arg.fields,
499
+ };
500
+ return isDataTypeMatch(genericsAlreadySelected, genericTypes, fakeArgRecord, fakeParamRecord);
501
+ }
502
+ else {
503
+ return { dataTypeMatch: false, genericsSet: [] };
504
+ }
505
+ }
506
+ else if (paramT.type === 'record' && arg.type === 'record') {
507
+ const genericsSet = [];
508
+ const paramFieldsByName = new Map();
509
+ for (const field of paramT.fields) {
510
+ paramFieldsByName.set((_a = field.as) !== null && _a !== void 0 ? _a : field.name, field);
511
+ }
512
+ for (const field of arg.fields) {
513
+ const match = paramFieldsByName.get((_b = field.as) !== null && _b !== void 0 ? _b : field.name);
514
+ if (match === undefined) {
515
+ return { dataTypeMatch: false, genericsSet: [] };
516
+ }
517
+ const result = isDataTypeMatch(new Map([
518
+ ...genericsAlreadySelected.entries(),
519
+ ...genericsSet.map(x => [x.name, x.type]),
520
+ ]), genericTypes, field, match);
521
+ genericsSet.push(...result.genericsSet);
522
+ }
523
+ return { dataTypeMatch: true, genericsSet };
524
+ }
525
+ else if (paramT.type === 'generic') {
526
+ const alreadySelected = genericsAlreadySelected.get(paramT.generic);
527
+ if (alreadySelected !== undefined &&
528
+ alreadySelected.type !== 'null' &&
529
+ alreadySelected.type !== 'error') {
530
+ return isDataTypeMatch(genericsAlreadySelected, genericTypes, arg, alreadySelected);
531
+ }
532
+ const allowedTypes = (_d = (_c = genericTypes.find(t => t.name === paramT.generic)) === null || _c === void 0 ? void 0 : _c.acceptibleTypes) !== null && _d !== void 0 ? _d : [];
533
+ for (const type of allowedTypes) {
534
+ const result = isDataTypeMatch(genericsAlreadySelected, genericTypes, arg, type);
535
+ if (result.dataTypeMatch) {
536
+ if (!(0, malloy_types_1.isAtomic)(arg) && arg.type !== 'null') {
537
+ continue;
538
+ }
539
+ const newGenericSet = {
540
+ name: paramT.generic,
541
+ type: arg,
542
+ };
543
+ return {
544
+ dataTypeMatch: true,
545
+ genericsSet: [...result.genericsSet, newGenericSet],
546
+ };
547
+ }
548
+ }
549
+ }
550
+ return { dataTypeMatch: false, genericsSet: [] };
551
+ }
552
+ function resolveGenerics(returnType, genericsSelected) {
553
+ switch (returnType.type) {
554
+ case 'array': {
555
+ if ('fields' in returnType) {
556
+ const fields = returnType.fields.map(f => {
557
+ const type = resolveGenerics(f, genericsSelected);
558
+ return {
559
+ ...f,
560
+ ...type,
561
+ };
562
+ });
563
+ return {
564
+ error: undefined,
565
+ returnType: {
566
+ type: 'array',
567
+ elementTypeDef: returnType.elementTypeDef,
568
+ fields,
569
+ },
570
+ };
571
+ }
572
+ const resolve = resolveGenerics(returnType.elementTypeDef, genericsSelected);
573
+ if (resolve.error) {
574
+ return resolve;
575
+ }
576
+ const elementTypeDef = resolve.returnType;
577
+ if (elementTypeDef.type === 'record') {
578
+ return {
579
+ error: undefined,
580
+ returnType: {
581
+ type: 'array',
582
+ elementTypeDef: { type: 'record_element' },
583
+ fields: elementTypeDef.fields,
584
+ },
585
+ };
586
+ }
587
+ if (!(0, malloy_types_1.isAtomic)(elementTypeDef)) {
588
+ return {
589
+ error: {
590
+ code: 'invalid-resolved-type-for-array',
591
+ parameters: 'Invalid resolved type for array; cannot be non-atomic',
592
+ },
593
+ returnType: undefined,
594
+ };
595
+ }
596
+ return {
597
+ error: undefined,
598
+ returnType: { type: 'array', elementTypeDef },
599
+ };
600
+ }
601
+ case 'record': {
602
+ const fields = returnType.fields.map(f => {
603
+ const type = resolveGenerics(f, genericsSelected);
604
+ return {
605
+ ...f,
606
+ ...type,
607
+ };
608
+ });
609
+ return { error: undefined, returnType: { type: 'record', fields } };
610
+ }
611
+ case 'generic': {
612
+ const resolved = genericsSelected.get(returnType.generic);
613
+ if (resolved === undefined) {
614
+ return {
615
+ error: {
616
+ code: 'generic-not-resolved',
617
+ parameters: `Generic ${returnType.generic} in return type could not be resolved`,
618
+ },
619
+ returnType: undefined,
620
+ };
621
+ }
622
+ return {
623
+ error: undefined,
624
+ returnType: resolved,
625
+ };
626
+ }
627
+ default:
628
+ return { error: undefined, returnType };
629
+ }
630
+ }
465
631
  //# sourceMappingURL=expr-func.js.map
@@ -26,6 +26,7 @@ class DialectNameSpace {
26
26
  supportsOrderBy: overload.supportsOrderBy,
27
27
  supportsLimit: overload.supportsLimit,
28
28
  isSymmetric: overload.isSymmetric,
29
+ genericTypes: overload.genericTypes,
29
30
  dialect: {
30
31
  [dialect.name]: {
31
32
  e: overload.e,
@@ -82,6 +82,7 @@ function getDialectFunctions() {
82
82
  dialect: {},
83
83
  supportsOrderBy: baseOverload.supportsOrderBy,
84
84
  supportsLimit: baseOverload.supportsLimit,
85
+ genericTypes: baseOverload.genericTypes,
85
86
  isSymmetric: baseOverload.isSymmetric,
86
87
  };
87
88
  for (const dialect of dialects) {
@@ -357,6 +357,8 @@ type MessageParameterTypes = {
357
357
  'exclude-after-include': string;
358
358
  'cannot-rename-non-field': string;
359
359
  'array-values-incompatible': string;
360
+ 'invalid-resolved-type-for-array': string;
361
+ 'generic-not-resolved': string;
360
362
  'cannot-tag-include-except': string;
361
363
  'unsupported-path-in-include': string;
362
364
  'wildcard-include-rename': string;
@@ -364,6 +366,11 @@ type MessageParameterTypes = {
364
366
  export declare const MESSAGE_FORMATTERS: PartialErrorCodeMessageMap;
365
367
  export type MessageCode = keyof MessageParameterTypes;
366
368
  export type MessageParameterType<T extends MessageCode> = MessageParameterTypes[T];
369
+ type MessageCodeAndParameters<T extends MessageCode> = {
370
+ code: T;
371
+ parameters: MessageParameterType<T>;
372
+ };
373
+ export type AnyMessageCodeAndParameters = MessageCodeAndParameters<MessageCode>;
367
374
  type MessageFormatter<T extends MessageCode> = MessageInfo | ((parameters: MessageParameterType<T>) => MessageInfo);
368
375
  type ErrorCodeMessageMap = {
369
376
  [key in keyof MessageParameterTypes]: MessageFormatter<key>;
@@ -414,6 +414,7 @@ export interface RepeatedRecordDef extends RepeatedRecordTypeDef, StructDefBase,
414
414
  }
415
415
  export type ArrayTypeDef = ScalarArrayTypeDef | RepeatedRecordTypeDef;
416
416
  export type ArrayDef = ScalarArrayDef | RepeatedRecordDef;
417
+ export declare function isRepeatedRecordFunctionParam(paramT: FunctionParameterTypeDef): paramT is RepeatedRecordFunctionParameterTypeDef;
417
418
  export declare function isRepeatedRecord(fd: FieldDef | QueryFieldDef | StructDef | AtomicTypeDef): fd is RepeatedRecordTypeDef;
418
419
  export declare function isScalarArray(td: AtomicTypeDef | FieldDef | QueryFieldDef | StructDef): td is ScalarArrayTypeDef;
419
420
  export interface ErrorTypeDef {
@@ -630,7 +631,7 @@ export type SourceDef = TableSourceDef | SQLSourceDef | QuerySourceDef | QueryRe
630
631
  /** Is this the "FROM" table of a query tree */
631
632
  export declare function isBaseTable(def: StructDef): def is SourceDef;
632
633
  export type StructDef = SourceDef | RecordDef | ArrayDef;
633
- export type NonAtomicType = Exclude<JoinElementType, 'array' | 'record'> | 'turtle' | 'null' | 'duration' | 'any' | 'regular expression';
634
+ export type NonAtomicType = Exclude<JoinElementType, 'array' | 'record'> | 'turtle' | 'null' | 'duration' | 'regular expression';
634
635
  export interface NonAtomicTypeDef {
635
636
  type: NonAtomicType;
636
637
  }
@@ -643,13 +644,54 @@ export type TypeInfo = {
643
644
  compositeFieldUsage: CompositeFieldUsage;
644
645
  };
645
646
  export type TypeDesc = ExpressionValueTypeDef & TypeInfo;
646
- export type FunctionParamType = ExpressionValueTypeDef | {
647
- type: 'any';
647
+ export type FunctionParameterTypeDef = ExpressionValueExtTypeDef<FunctionParameterTypeExtensions>;
648
+ export type FunctionParamTypeDesc = FunctionParameterTypeDef & {
649
+ expressionType: ExpressionType | undefined;
650
+ evalSpace: EvalSpace;
648
651
  };
649
- export type FunctionParamTypeDesc = FunctionParamType & {
652
+ interface ScalarArrayExtTypeDef<TypeExtensions> {
653
+ type: 'array';
654
+ elementTypeDef: Exclude<ExpressionValueExtTypeDef<TypeExtensions>, RecordExtTypeDef<TypeExtensions>>;
655
+ }
656
+ type ExpressionValueExtTypeDef<TypeExtensions> = AtomicTypeDef | NonAtomicTypeDef | ScalarArrayExtTypeDef<TypeExtensions> | RecordExtTypeDef<TypeExtensions> | RepeatedRecordExtTypeDef<TypeExtensions> | TypeExtensions;
657
+ interface RecordExtTypeDef<TypeExtensions> {
658
+ type: 'record';
659
+ fields: ExtFieldDef<TypeExtensions>[];
660
+ }
661
+ type ExtFieldDef<TypeExtensions> = FieldDef | (TypeExtensions & FieldBase);
662
+ interface RepeatedRecordExtTypeDef<TypeExtensions> {
663
+ type: 'array';
664
+ elementTypeDef: RecordElementTypeDef;
665
+ fields: ExtFieldDef<TypeExtensions>[];
666
+ }
667
+ type FunctionReturnTypeExtensions = GenericTypeDef;
668
+ export type ScalarArrayFunctionReturnTypeDef = ScalarArrayExtTypeDef<FunctionReturnTypeExtensions>;
669
+ export type FunctionReturnFieldDef = ExtFieldDef<FunctionReturnTypeExtensions>;
670
+ export type RecordFunctionReturnTypeDef = RecordExtTypeDef<FunctionReturnTypeExtensions>;
671
+ export type RepeatedRecordFunctionReturnTypeDef = RepeatedRecordExtTypeDef<FunctionReturnTypeExtensions>;
672
+ type FunctionParameterTypeExtensions = GenericTypeDef | AnyTypeDef;
673
+ export type ScalarArrayFunctionParameterTypeDef = ScalarArrayExtTypeDef<FunctionParameterTypeExtensions>;
674
+ export type FunctionParameterFieldDef = ExtFieldDef<FunctionParameterTypeExtensions>;
675
+ export type RecordFunctionParameterTypeDef = RecordExtTypeDef<FunctionParameterTypeExtensions>;
676
+ export type RepeatedRecordFunctionParameterTypeDef = RepeatedRecordExtTypeDef<FunctionParameterTypeExtensions>;
677
+ type FunctionGenericTypeExtensions = AnyTypeDef;
678
+ export type ScalarArrayFunctionGenericTypeDef = ScalarArrayExtTypeDef<FunctionGenericTypeExtensions>;
679
+ export type FunctionGenericFieldDef = ExtFieldDef<FunctionGenericTypeExtensions>;
680
+ export type RecordFunctionGenericTypeDef = RecordExtTypeDef<FunctionGenericTypeExtensions>;
681
+ export type RepeatedRecordFunctionGenericTypeDef = RepeatedRecordExtTypeDef<FunctionGenericTypeExtensions>;
682
+ export interface GenericTypeDef {
683
+ type: 'generic';
684
+ generic: string;
685
+ }
686
+ export interface AnyTypeDef {
687
+ type: 'any';
688
+ }
689
+ export type TypeDescExtensions = {
650
690
  expressionType: ExpressionType | undefined;
651
691
  evalSpace: EvalSpace;
652
692
  };
693
+ export type FunctionReturnTypeDef = ExpressionValueExtTypeDef<FunctionReturnTypeExtensions>;
694
+ export type FunctionReturnTypeDesc = FunctionReturnTypeDef & TypeDescExtensions;
653
695
  export type EvalSpace = 'constant' | 'input' | 'output' | 'literal';
654
696
  export declare function isLiteral(evalSpace: EvalSpace): boolean;
655
697
  export declare function mergeEvalSpaces(...evalSpaces: EvalSpace[]): EvalSpace;
@@ -658,12 +700,17 @@ export interface FunctionParameterDef {
658
700
  allowedTypes: FunctionParamTypeDesc[];
659
701
  isVariadic: boolean;
660
702
  }
703
+ export type FunctionGenericTypeDef = ExpressionValueExtTypeDef<FunctionGenericTypeExtensions>;
661
704
  export interface FunctionOverloadDef {
662
- returnType: TypeDesc;
705
+ returnType: FunctionReturnTypeDesc;
663
706
  isSymmetric?: boolean;
664
707
  params: FunctionParameterDef[];
665
708
  supportsOrderBy?: boolean | 'only_default';
666
709
  supportsLimit?: boolean;
710
+ genericTypes?: {
711
+ name: string;
712
+ acceptibleTypes: FunctionGenericTypeDef[];
713
+ }[];
667
714
  dialect: {
668
715
  [dialect: string]: {
669
716
  e: Expr;
@@ -776,7 +823,7 @@ export interface QueryResult extends CompiledQuery {
776
823
  profilingUrl?: string;
777
824
  }
778
825
  export declare function isTurtle(def: TypedDef): def is TurtleDef;
779
- export declare function isAtomic(def: TypedDef): def is AtomicTypeDef;
826
+ export declare function isAtomic(def: TypedDef | ExpressionValueTypeDef): def is AtomicTypeDef;
780
827
  export interface SearchResultRow {
781
828
  field_name: string;
782
829
  field_value: string;
@@ -810,7 +857,7 @@ export interface PrepareResultOptions {
810
857
  replaceMaterializedReferences?: boolean;
811
858
  materializedTablePrefix?: string;
812
859
  }
813
- type UTD = AtomicTypeDef | FunctionParamTypeDesc | undefined;
860
+ type UTD = AtomicTypeDef | TypedDef | FunctionParameterTypeDef | FunctionReturnTypeDef | undefined;
814
861
  /**
815
862
  * A set of utilities for asking questions TypeDef/TypeDesc
816
863
  * (which is OK because TypeDesc is an extension of a TypeDef)
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  /*
3
3
  * Copyright 2023 Google LLC
4
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
5
  *
5
6
  * Permission is hereby granted, free of charge, to any person obtaining
6
7
  * a copy of this software and associated documentation files
@@ -22,8 +23,8 @@
22
23
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24
  */
24
25
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.isBaseTable = exports.isSourceDef = exports.sourceBase = exports.isSegmentSQL = exports.isIndexSegment = exports.isRawSegment = exports.isSamplingEnable = exports.isSamplingPercent = exports.isSamplingRows = exports.isQuerySegment = exports.isProjectSegment = exports.isPartialSegment = exports.isReduceSegment = exports.structHasErrors = exports.segmentHasErrors = exports.refIsStructDef = exports.ValueType = exports.isExtractUnit = exports.isTimestampUnit = exports.isDateUnit = exports.isJoinedSource = exports.isJoined = exports.isJoinable = exports.isMatrixOperation = exports.isScalarArray = exports.isRepeatedRecord = exports.mkArrayDef = exports.mkFieldDef = exports.fieldIsIntrinsic = exports.isCastType = exports.canOrderBy = exports.isAtomicFieldType = exports.isTemporalType = exports.hasExpression = exports.maxOfExpressionTypes = exports.maxExpressionType = exports.isExpressionTypeLEQ = exports.expressionIsAnalytic = exports.expressionIsCalculation = exports.expressionInvolvesAggregate = exports.expressionIsUngroupedAggregate = exports.expressionIsAggregate = exports.expressionIsScalar = exports.paramHasValue = exports.isRawCast = exports.mkTemporal = exports.isAsymmetricExpr = exports.exprIsLeaf = exports.exprHasE = exports.exprHasKids = void 0;
26
- exports.TD = exports.isValueDate = exports.isValueTimestamp = exports.isValueBoolean = exports.isValueNumber = exports.isValueString = exports.isAtomic = exports.isTurtle = exports.getIdentifier = exports.isLeafAtomic = exports.mergeEvalSpaces = exports.isLiteral = void 0;
26
+ exports.isSourceDef = exports.sourceBase = exports.isSegmentSQL = exports.isIndexSegment = exports.isRawSegment = exports.isSamplingEnable = exports.isSamplingPercent = exports.isSamplingRows = exports.isQuerySegment = exports.isProjectSegment = exports.isPartialSegment = exports.isReduceSegment = exports.structHasErrors = exports.segmentHasErrors = exports.refIsStructDef = exports.ValueType = exports.isExtractUnit = exports.isTimestampUnit = exports.isDateUnit = exports.isJoinedSource = exports.isJoined = exports.isJoinable = exports.isMatrixOperation = exports.isScalarArray = exports.isRepeatedRecord = exports.isRepeatedRecordFunctionParam = exports.mkArrayDef = exports.mkFieldDef = exports.fieldIsIntrinsic = exports.isCastType = exports.canOrderBy = exports.isAtomicFieldType = exports.isTemporalType = exports.hasExpression = exports.maxOfExpressionTypes = exports.maxExpressionType = exports.isExpressionTypeLEQ = exports.expressionIsAnalytic = exports.expressionIsCalculation = exports.expressionInvolvesAggregate = exports.expressionIsUngroupedAggregate = exports.expressionIsAggregate = exports.expressionIsScalar = exports.paramHasValue = exports.isRawCast = exports.mkTemporal = exports.isAsymmetricExpr = exports.exprIsLeaf = exports.exprHasE = exports.exprHasKids = void 0;
27
+ exports.TD = exports.isValueDate = exports.isValueTimestamp = exports.isValueBoolean = exports.isValueNumber = exports.isValueString = exports.isAtomic = exports.isTurtle = exports.getIdentifier = exports.isLeafAtomic = exports.mergeEvalSpaces = exports.isLiteral = exports.isBaseTable = void 0;
27
28
  function exprHasKids(e) {
28
29
  return 'kids' in e;
29
30
  }
@@ -217,6 +218,10 @@ function mkArrayDef(ofType, name) {
217
218
  };
218
219
  }
219
220
  exports.mkArrayDef = mkArrayDef;
221
+ function isRepeatedRecordFunctionParam(paramT) {
222
+ return (paramT.type === 'array' && paramT.elementTypeDef.type === 'record_element');
223
+ }
224
+ exports.isRepeatedRecordFunctionParam = isRepeatedRecordFunctionParam;
220
225
  function isRepeatedRecord(fd) {
221
226
  return fd.type === 'array' && fd.elementTypeDef.type === 'record_element';
222
227
  }
@@ -477,10 +482,10 @@ exports.TD = {
477
482
  ) {
478
483
  return exports.TD.eq(x.elementTypeDef, y.elementTypeDef);
479
484
  }
480
- return checkFields(x, y);
485
+ return exports.TD.isAtomic(x) && exports.TD.isAtomic(y) && checkFields(x, y);
481
486
  }
482
487
  else if (x.type === 'record' && y.type === 'record') {
483
- return checkFields(x, y);
488
+ return exports.TD.isAtomic(x) && exports.TD.isAtomic(y) && checkFields(x, y);
484
489
  }
485
490
  if (x.type === 'sql native' && y.type === 'sql native') {
486
491
  return x.rawType !== undefined && x.rawType === y.rawType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.223-dev241213043533",
3
+ "version": "0.0.223-dev241216191808",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",