@malloydata/malloy 0.0.223-dev241213043533 → 0.0.223-dev241216182944

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,6 +7,12 @@
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',
@@ -65,6 +71,7 @@ const string_agg_distinct = {
65
71
  },
66
72
  };
67
73
  exports.DUCKDB_DIALECT_FUNCTIONS = {
74
+ list_extract,
68
75
  count_approx,
69
76
  dayname,
70
77
  to_timestamp,
@@ -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,35 @@ 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>;
56
71
  }
57
- export type TypeDescElementBlueprint = LeafExpressionType | ArrayBlueprint | RecordBlueprint;
58
- export type TypeDescBlueprint = TypeDescElementBlueprint | {
72
+ export type LeafPlusType = LeafExpressionType | 'any';
73
+ export type TypeDescElementBlueprint = LeafPlusType | ArrayBlueprint | RecordBlueprint;
74
+ export type NamedGeneric = {
59
75
  generic: string;
76
+ };
77
+ export type TypeDescBlueprint = TypeDescElementBlueprintOrNamedGeneric | {
78
+ literal: TypeDescElementBlueprintOrNamedGeneric;
60
79
  } | {
61
- literal: LeafExpressionType | {
62
- generic: string;
63
- };
80
+ constant: TypeDescElementBlueprintOrNamedGeneric;
64
81
  } | {
65
- constant: LeafExpressionType | {
66
- generic: string;
67
- };
82
+ dimension: TypeDescElementBlueprintOrNamedGeneric;
68
83
  } | {
69
- dimension: LeafExpressionType | {
70
- generic: string;
71
- };
84
+ measure: TypeDescElementBlueprintOrNamedGeneric;
72
85
  } | {
73
- measure: LeafExpressionType | {
74
- generic: string;
75
- };
76
- } | {
77
- calculation: LeafExpressionType | {
78
- generic: string;
79
- };
86
+ calculation: TypeDescElementBlueprintOrNamedGeneric;
80
87
  };
81
88
  type ParamTypeBlueprint = TypeDescBlueprint | TypeDescBlueprint[] | {
82
89
  variadic: TypeDescBlueprint | TypeDescBlueprint[];
83
90
  };
84
91
  export interface SignatureBlueprint {
85
- generic?: [string, LeafExpressionType[]];
92
+ generic?: {
93
+ [name: string]: TypeDescElementBlueprintOrNamedGeneric[];
94
+ };
86
95
  takes: {
87
96
  [name: string]: ParamTypeBlueprint;
88
97
  };
@@ -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,83 @@ 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
+ throw new Error('Cannot figure out type');
199
+ }
200
+ function expandReturnTypeBlueprint(blueprint) {
201
+ if (blueprint === 'any') {
202
+ throw new Error('Cannot return any type');
203
+ }
204
+ if (typeof blueprint === 'string') {
205
+ return minScalar({ type: blueprint });
206
+ }
207
+ else if ('array' in blueprint) {
208
+ return anyExprType(expandTypeDescElementBlueprint(blueprint, false));
209
+ }
210
+ else if ('record' in blueprint) {
211
+ return anyExprType(expandTypeDescElementBlueprint(blueprint, false));
212
+ }
213
+ else if ('generic' in blueprint) {
214
+ return minScalar(expandTypeDescElementBlueprint(blueprint, false));
217
215
  }
218
216
  else if ('literal' in blueprint) {
219
- base = literal(minScalar(removeGeneric(blueprint.literal, generic)));
217
+ return literal(minScalar(expandTypeDescElementBlueprint(blueprint.literal, false)));
220
218
  }
221
219
  else if ('constant' in blueprint) {
222
- base = constant(minScalar(removeGeneric(blueprint.constant, generic)));
220
+ return constant(minScalar(expandTypeDescElementBlueprint(blueprint.constant, false)));
223
221
  }
224
222
  else if ('dimension' in blueprint) {
225
- base = minScalar(removeGeneric(blueprint.dimension, generic));
223
+ return minScalar(expandTypeDescElementBlueprint(blueprint.dimension, false));
226
224
  }
227
225
  else if ('measure' in blueprint) {
228
- base = minAggregate(removeGeneric(blueprint.measure, generic));
226
+ return minAggregate(expandTypeDescElementBlueprint(blueprint.measure, false));
229
227
  }
230
228
  else {
231
- base = minAnalytic(removeGeneric(blueprint.calculation, generic));
229
+ return minAnalytic(expandTypeDescElementBlueprint(blueprint.calculation, false));
232
230
  }
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
231
  }
239
232
  function isTypeDescBlueprint(blueprint) {
240
233
  return (typeof blueprint === 'string' ||
@@ -261,51 +254,51 @@ function extractParamTypeBlueprints(blueprint) {
261
254
  return blueprint.variadic;
262
255
  }
263
256
  }
264
- function expandParamTypeBlueprint(blueprint, generic) {
257
+ function expandParamTypeBlueprint(blueprint) {
265
258
  if (typeof blueprint === 'string') {
266
- return anyExprType(blueprint);
259
+ return anyExprType({ type: blueprint });
267
260
  }
268
261
  else if ('generic' in blueprint) {
269
- return anyExprType(removeGeneric(blueprint, generic));
262
+ return anyExprType(expandTypeDescElementBlueprint(blueprint));
270
263
  }
271
264
  else if ('literal' in blueprint) {
272
- return literal(maxScalar(removeGeneric(blueprint.literal, generic)));
265
+ return literal(maxScalar(expandTypeDescElementBlueprint(blueprint.literal)));
273
266
  }
274
267
  else if ('constant' in blueprint) {
275
- return constant(maxScalar(removeGeneric(blueprint.constant, generic)));
268
+ return constant(maxScalar(expandTypeDescElementBlueprint(blueprint.constant)));
276
269
  }
277
270
  else if ('dimension' in blueprint) {
278
- return maxScalar(removeGeneric(blueprint.dimension, generic));
271
+ return maxScalar(expandTypeDescElementBlueprint(blueprint.dimension));
279
272
  }
280
273
  else if ('measure' in blueprint) {
281
- return maxAggregate(removeGeneric(blueprint.measure, generic));
274
+ return maxAggregate(expandTypeDescElementBlueprint(blueprint.measure));
282
275
  }
283
276
  else if ('array' in blueprint) {
284
- return anyExprTypeBP(blueprint, generic);
277
+ return anyExprType(expandTypeDescElementBlueprint(blueprint, false));
285
278
  }
286
279
  else if ('record' in blueprint) {
287
- return anyExprTypeBP(blueprint, generic);
280
+ return anyExprType(expandTypeDescElementBlueprint(blueprint, false));
288
281
  }
289
282
  else {
290
- return maxAnalytic(removeGeneric(blueprint.calculation, generic));
283
+ return maxAnalytic(expandTypeDescElementBlueprint(blueprint.calculation));
291
284
  }
292
285
  }
293
- function expandParamTypeBlueprints(blueprints, generic) {
294
- return blueprints.map(blueprint => expandParamTypeBlueprint(blueprint, generic));
286
+ function expandParamTypeBlueprints(blueprints) {
287
+ return blueprints.map(blueprint => expandParamTypeBlueprint(blueprint));
295
288
  }
296
289
  function isVariadicParamBlueprint(blueprint) {
297
290
  return typeof blueprint !== 'string' && 'variadic' in blueprint;
298
291
  }
299
- function expandParamBlueprint(name, blueprint, generic) {
292
+ function expandParamBlueprint(name, blueprint) {
300
293
  return {
301
294
  name,
302
- allowedTypes: expandParamTypeBlueprints(extractParamTypeBlueprints(blueprint), generic),
295
+ allowedTypes: expandParamTypeBlueprints(extractParamTypeBlueprints(blueprint)),
303
296
  isVariadic: isVariadicParamBlueprint(blueprint),
304
297
  };
305
298
  }
306
- function expandParamsBlueprints(blueprints, generic) {
299
+ function expandParamsBlueprints(blueprints) {
307
300
  const paramsArray = Object.entries(blueprints);
308
- return paramsArray.map(blueprint => expandParamBlueprint(blueprint[0], blueprint[1], generic));
301
+ return paramsArray.map(blueprint => expandParamBlueprint(blueprint[0], blueprint[1]));
309
302
  }
310
303
  function expandBlueprintSqlInterpolation(sql) {
311
304
  const src = [];
@@ -393,23 +386,25 @@ function expandImplBlueprint(blueprint) {
393
386
  defaultOrderByArgIndex: blueprint.impl.defaultOrderByArgIndex,
394
387
  };
395
388
  }
396
- function expandOneBlueprint(blueprint, generic) {
389
+ function expandGenericDefinitions(blueprint) {
390
+ if (blueprint === undefined)
391
+ return undefined;
392
+ return Object.entries(blueprint).map(([name, acceptibleTypes]) => ({
393
+ name: name,
394
+ acceptibleTypes: acceptibleTypes.map(t => expandTypeDescElementBlueprint(t, true, false)),
395
+ }));
396
+ }
397
+ function expandBlueprint(blueprint) {
397
398
  return {
398
- returnType: expandReturnTypeBlueprint(blueprint.returns, generic),
399
- params: expandParamsBlueprints(blueprint.takes, generic),
399
+ returnType: expandReturnTypeBlueprint(blueprint.returns),
400
+ params: expandParamsBlueprints(blueprint.takes),
400
401
  isSymmetric: blueprint.isSymmetric,
401
402
  supportsOrderBy: blueprint.supportsOrderBy,
402
403
  supportsLimit: blueprint.supportsLimit,
404
+ genericTypes: expandGenericDefinitions(blueprint.generic),
403
405
  ...expandImplBlueprint(blueprint),
404
406
  };
405
407
  }
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
408
  function isDefinitionBlueprint(blueprint) {
414
409
  return 'takes' in blueprint && 'returns' in blueprint && 'impl' in blueprint;
415
410
  }
@@ -418,7 +413,7 @@ function isImplementationBlueprint(blueprint) {
418
413
  }
419
414
  function expandOverloadedBlueprint(blueprint) {
420
415
  if (isDefinitionBlueprint(blueprint)) {
421
- return expandBlueprint(blueprint);
416
+ return [expandBlueprint(blueprint)];
422
417
  }
423
418
  else {
424
419
  return Object.values(blueprint).flatMap(overload => expandBlueprint(overload));
@@ -433,7 +428,7 @@ function expandBlueprintMap(blueprints) {
433
428
  }
434
429
  exports.expandBlueprintMap = expandBlueprintMap;
435
430
  function expandImplementationBlueprint(base, impl) {
436
- return expandBlueprint({ ...base, impl });
431
+ return [expandBlueprint({ ...base, impl })];
437
432
  }
438
433
  function expandOverloadedOverrideBlueprint(name, base, blueprint) {
439
434
  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-dev241216182944",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",