@malloydata/malloy 0.0.393 → 0.0.394
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.
- package/dist/api/foundation/core.d.ts +0 -4
- package/dist/api/foundation/core.js +13 -10
- package/dist/lang/ast/expressions/expr-compare.d.ts +15 -0
- package/dist/lang/ast/expressions/expr-compare.js +82 -2
- package/dist/lang/ast/statements/define-given.d.ts +2 -1
- package/dist/lang/ast/statements/define-given.js +52 -1
- package/dist/lang/ast/types/malloy-element.js +2 -0
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +188 -167
- package/dist/lang/lib/Malloy/MalloyParser.js +2582 -2442
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +24 -0
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +15 -0
- package/dist/lang/malloy-to-ast.d.ts +9 -2
- package/dist/lang/malloy-to-ast.js +37 -2
- package/dist/lang/parse-log.d.ts +22 -0
- package/dist/lang/parse-log.js +6 -0
- package/dist/lang/test/expr-to-str.js +3 -0
- package/dist/model/expression_compiler.js +38 -11
- package/dist/model/given_binding.d.ts +15 -0
- package/dist/model/given_binding.js +35 -0
- package/dist/model/inline_expr.d.ts +30 -0
- package/dist/model/inline_expr.js +184 -0
- package/dist/model/malloy_types.d.ts +19 -1
- package/dist/model/query_query.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -278,10 +278,6 @@ export declare class Model implements Taggable {
|
|
|
278
278
|
* The givens this model surfaces, keyed by caller-facing surface name.
|
|
279
279
|
* Used by whole-model parameter-editor UIs to render input widgets for
|
|
280
280
|
* every given the model can accept.
|
|
281
|
-
*
|
|
282
|
-
* Internal-only givens (declared but never surfaced into the namespace,
|
|
283
|
-
* resolved purely via defaults) are NOT in this map — the caller has no
|
|
284
|
-
* way to set them, so listing them would mislead a UI.
|
|
285
281
|
*/
|
|
286
282
|
get givens(): ReadonlyMap<string, Given>;
|
|
287
283
|
tagParse(spec?: TagParseSpec): MalloyTagParse;
|
|
@@ -782,10 +782,6 @@ class Model {
|
|
|
782
782
|
* The givens this model surfaces, keyed by caller-facing surface name.
|
|
783
783
|
* Used by whole-model parameter-editor UIs to render input widgets for
|
|
784
784
|
* every given the model can accept.
|
|
785
|
-
*
|
|
786
|
-
* Internal-only givens (declared but never surfaced into the namespace,
|
|
787
|
-
* resolved purely via defaults) are NOT in this map — the caller has no
|
|
788
|
-
* way to set them, so listing them would mislead a UI.
|
|
789
785
|
*/
|
|
790
786
|
get givens() {
|
|
791
787
|
var _a, _b;
|
|
@@ -799,9 +795,9 @@ class Model {
|
|
|
799
795
|
if ((_b = (_a = this.runtimeContext) === null || _a === void 0 ? void 0 : _a.finalizedGivens) === null || _b === void 0 ? void 0 : _b.has(surfaceName))
|
|
800
796
|
continue;
|
|
801
797
|
const decl = givens[entry.id];
|
|
802
|
-
if (!decl)
|
|
803
|
-
|
|
804
|
-
|
|
798
|
+
if (decl && !decl.inline) {
|
|
799
|
+
out.set(surfaceName, new Given(surfaceName, entry.id, decl));
|
|
800
|
+
}
|
|
805
801
|
}
|
|
806
802
|
return out;
|
|
807
803
|
}
|
|
@@ -1197,11 +1193,18 @@ class PreparedQuery {
|
|
|
1197
1193
|
*/
|
|
1198
1194
|
getPreparedResult(options) {
|
|
1199
1195
|
const queryModel = this._model.queryModel;
|
|
1196
|
+
// Build the resolved-givens map in two phases:
|
|
1197
|
+
// 1. caller-supplied values (resolveSuppliedGivens)
|
|
1198
|
+
// 2. inline-given defaults eager-evaluated against the map
|
|
1199
|
+
// Result is undefined when no values land — preserves the previous
|
|
1200
|
+
// "no givens path" downstream.
|
|
1201
|
+
const resolved = (options === null || options === void 0 ? void 0 : options.givens)
|
|
1202
|
+
? (0, given_binding_1.resolveSuppliedGivens)(options.givens, this._modelDef)
|
|
1203
|
+
: new Map();
|
|
1204
|
+
(0, given_binding_1.evaluateInlineGivens)(resolved, this._modelDef);
|
|
1200
1205
|
const prepareResultOptions = {
|
|
1201
1206
|
...options,
|
|
1202
|
-
resolvedGivens:
|
|
1203
|
-
? (0, given_binding_1.resolveSuppliedGivens)(options.givens, this._modelDef)
|
|
1204
|
-
: undefined,
|
|
1207
|
+
resolvedGivens: resolved.size > 0 ? resolved : undefined,
|
|
1205
1208
|
};
|
|
1206
1209
|
const translatedQuery = queryModel.compileQuery(this._query, prepareResultOptions);
|
|
1207
1210
|
return new PreparedResult({
|
|
@@ -3,6 +3,7 @@ import type { ExprValue } from '../types/expr-value';
|
|
|
3
3
|
import { ExpressionDef } from '../types/expression-def';
|
|
4
4
|
import type { FieldSpace } from '../types/field-space';
|
|
5
5
|
import { BinaryBoolean } from './binary-boolean';
|
|
6
|
+
import type { GivenReference } from './expr-given';
|
|
6
7
|
export declare class ExprCompare extends BinaryBoolean<CompareMalloyOperator> {
|
|
7
8
|
elementType: string;
|
|
8
9
|
constructor(left: ExpressionDef, op: CompareMalloyOperator, right: ExpressionDef);
|
|
@@ -28,3 +29,17 @@ export declare class ExprLegacyIn extends ExpressionDef {
|
|
|
28
29
|
constructor(expr: ExpressionDef, notIn: boolean, choices: ExpressionDef[]);
|
|
29
30
|
getExpression(fs: FieldSpace): ExprValue;
|
|
30
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* `expr in $ARRAY_GIVEN` — runtime test of a basic-typed expression
|
|
34
|
+
* against the elements of a runtime-bound array given. The translator
|
|
35
|
+
* verifies the given is `T[]` and the LHS is the same basic `T`; SQL
|
|
36
|
+
* emission expands the bound array's elements at compile time.
|
|
37
|
+
*/
|
|
38
|
+
export declare class ExprInGiven extends ExpressionDef {
|
|
39
|
+
readonly expr: ExpressionDef;
|
|
40
|
+
readonly notIn: boolean;
|
|
41
|
+
readonly givenRef: GivenReference;
|
|
42
|
+
elementType: string;
|
|
43
|
+
constructor(expr: ExpressionDef, notIn: boolean, givenRef: GivenReference);
|
|
44
|
+
getExpression(fs: FieldSpace): ExprValue;
|
|
45
|
+
}
|
|
@@ -55,9 +55,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
55
55
|
};
|
|
56
56
|
})();
|
|
57
57
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
-
exports.ExprLegacyIn = exports.ExprEquality = exports.ExprCompare = void 0;
|
|
58
|
+
exports.ExprInGiven = exports.ExprLegacyIn = exports.ExprEquality = exports.ExprCompare = void 0;
|
|
59
|
+
const malloy_types_1 = require("../../../model/malloy_types");
|
|
60
|
+
const utils_1 = require("../../../model/utils");
|
|
59
61
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
60
62
|
const expr_value_1 = require("../types/expr-value");
|
|
63
|
+
const expr_value_2 = require("../types/expr-value");
|
|
61
64
|
const expression_def_1 = require("../types/expression-def");
|
|
62
65
|
const binary_boolean_1 = require("./binary-boolean");
|
|
63
66
|
const compareTypes = {
|
|
@@ -112,7 +115,7 @@ class ExprLegacyIn extends expression_def_1.ExpressionDef {
|
|
|
112
115
|
getExpression(fs) {
|
|
113
116
|
const lookFor = this.expr.getExpression(fs);
|
|
114
117
|
const oneOf = this.choices.map(e => e.getExpression(fs));
|
|
115
|
-
return (0,
|
|
118
|
+
return (0, expr_value_2.computedExprValue)({
|
|
116
119
|
dataType: { type: 'boolean' },
|
|
117
120
|
value: {
|
|
118
121
|
node: 'in',
|
|
@@ -124,4 +127,81 @@ class ExprLegacyIn extends expression_def_1.ExpressionDef {
|
|
|
124
127
|
}
|
|
125
128
|
}
|
|
126
129
|
exports.ExprLegacyIn = ExprLegacyIn;
|
|
130
|
+
/**
|
|
131
|
+
* `expr in $ARRAY_GIVEN` — runtime test of a basic-typed expression
|
|
132
|
+
* against the elements of a runtime-bound array given. The translator
|
|
133
|
+
* verifies the given is `T[]` and the LHS is the same basic `T`; SQL
|
|
134
|
+
* emission expands the bound array's elements at compile time.
|
|
135
|
+
*/
|
|
136
|
+
class ExprInGiven extends expression_def_1.ExpressionDef {
|
|
137
|
+
constructor(expr, notIn, givenRef) {
|
|
138
|
+
super();
|
|
139
|
+
this.expr = expr;
|
|
140
|
+
this.notIn = notIn;
|
|
141
|
+
this.givenRef = givenRef;
|
|
142
|
+
this.elementType = 'inGiven';
|
|
143
|
+
this.has({ expr, givenRef });
|
|
144
|
+
}
|
|
145
|
+
getExpression(fs) {
|
|
146
|
+
const lookFor = this.expr.getExpression(fs);
|
|
147
|
+
const givenVal = this.givenRef.getExpression(fs);
|
|
148
|
+
// `in` is logically a boolean — every error path returns a
|
|
149
|
+
// boolean-typed error so a `where:` clause around us doesn't pile a
|
|
150
|
+
// "filter must be boolean" complaint on top of our own diagnostic.
|
|
151
|
+
const boolError = () => (0, expr_value_1.computedErrorExprValue)({
|
|
152
|
+
dataType: { type: 'boolean' },
|
|
153
|
+
error: 'in-given type error',
|
|
154
|
+
from: [lookFor, givenVal],
|
|
155
|
+
});
|
|
156
|
+
if (lookFor.type === 'error' || givenVal.type === 'error') {
|
|
157
|
+
return boolError();
|
|
158
|
+
}
|
|
159
|
+
// GivenReference only ever returns a `given` ExprValue on the
|
|
160
|
+
// success path; the error branch is filtered above. No other case
|
|
161
|
+
// is reachable here.
|
|
162
|
+
const givenNode = givenVal.value;
|
|
163
|
+
if (givenNode.node !== 'given') {
|
|
164
|
+
throw this.internalError(`expected GivenReference to produce a 'given' node, got '${givenNode.node}'`);
|
|
165
|
+
}
|
|
166
|
+
if (!malloy_types_1.TD.isAtomic(givenVal) || givenVal.type !== 'array') {
|
|
167
|
+
this.logError('in-given-rhs-not-array', {
|
|
168
|
+
givenName: this.givenRef.name,
|
|
169
|
+
actualType: malloy_types_1.TD.isAtomic(givenVal)
|
|
170
|
+
? (0, utils_1.typeDefToString)(givenVal)
|
|
171
|
+
: givenVal.type,
|
|
172
|
+
});
|
|
173
|
+
return boolError();
|
|
174
|
+
}
|
|
175
|
+
if ((0, malloy_types_1.isRepeatedRecord)(givenVal)) {
|
|
176
|
+
this.logError('in-given-rhs-not-basic-array', {
|
|
177
|
+
givenName: this.givenRef.name,
|
|
178
|
+
elementType: (0, utils_1.typeDefToString)(givenVal),
|
|
179
|
+
});
|
|
180
|
+
return boolError();
|
|
181
|
+
}
|
|
182
|
+
// givenVal is BasicArrayTypeDef-shaped — the union for array
|
|
183
|
+
// AtomicTypeDefs is BasicArray | RepeatedRecord, and the
|
|
184
|
+
// RepeatedRecord branch returned above.
|
|
185
|
+
const elemType = givenVal.elementTypeDef;
|
|
186
|
+
if (!malloy_types_1.TD.isBasicAtomic(lookFor) || lookFor.type !== elemType.type) {
|
|
187
|
+
this.logError('in-given-type-mismatch', {
|
|
188
|
+
lhsType: malloy_types_1.TD.isAtomic(lookFor) ? (0, utils_1.typeDefToString)(lookFor) : lookFor.type,
|
|
189
|
+
elementType: (0, utils_1.typeDefToString)(elemType),
|
|
190
|
+
});
|
|
191
|
+
return boolError();
|
|
192
|
+
}
|
|
193
|
+
const inGivenNode = {
|
|
194
|
+
node: 'inGiven',
|
|
195
|
+
not: this.notIn,
|
|
196
|
+
givenRef: givenNode,
|
|
197
|
+
e: lookFor.value,
|
|
198
|
+
};
|
|
199
|
+
return (0, expr_value_2.computedExprValue)({
|
|
200
|
+
dataType: { type: 'boolean' },
|
|
201
|
+
value: inGivenNode,
|
|
202
|
+
from: [lookFor, givenVal],
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
exports.ExprInGiven = ExprInGiven;
|
|
127
207
|
//# sourceMappingURL=expr-compare.js.map
|
|
@@ -7,12 +7,13 @@ import { extendNoteMethod } from '../types/noteable';
|
|
|
7
7
|
export declare class GivenDeclaration extends MalloyElement implements DocStatement, Noteable {
|
|
8
8
|
readonly name: string;
|
|
9
9
|
readonly typeDef: GivenTypeDef;
|
|
10
|
+
readonly inline: boolean;
|
|
10
11
|
elementType: string;
|
|
11
12
|
readonly isNoteableObj = true;
|
|
12
13
|
extendNote: typeof extendNoteMethod;
|
|
13
14
|
note?: Annotation;
|
|
14
15
|
readonly default?: ConstantExpression;
|
|
15
|
-
constructor(name: string, typeDef: GivenTypeDef, defaultExpr?: ConstantExpression);
|
|
16
|
+
constructor(name: string, typeDef: GivenTypeDef, defaultExpr?: ConstantExpression, inline?: boolean);
|
|
16
17
|
protected varInfo(): string;
|
|
17
18
|
execute(doc: Document): void;
|
|
18
19
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.DefineGivens = exports.GivenDeclaration = void 0;
|
|
8
8
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
9
|
+
const inline_expr_1 = require("../../../model/inline_expr");
|
|
9
10
|
const source_def_utils_1 = require("../../../model/source_def_utils");
|
|
10
11
|
const utils_1 = require("../../../model/utils");
|
|
11
12
|
const expression_def_1 = require("../types/expression-def");
|
|
@@ -20,11 +21,43 @@ function filterTypeMismatch(declared, constVal) {
|
|
|
20
21
|
return ((declared.type === 'filter expression') !==
|
|
21
22
|
(constVal.type === 'filter expression'));
|
|
22
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Walk an Expr tree and collect every node string that isn't in the
|
|
26
|
+
* allowed inline operator/leaf sets.
|
|
27
|
+
*
|
|
28
|
+
* The translator caller is gated on a clean translation of the default
|
|
29
|
+
* (`constVal.type !== 'error'`): we don't pile bad-operator errors on
|
|
30
|
+
* top of a default that didn't translate cleanly for more fundamental
|
|
31
|
+
* reasons (an unknown `$REF`, a type mismatch, etc.). Every bad node
|
|
32
|
+
* is collected so the author sees the full list in one diagnostic.
|
|
33
|
+
*/
|
|
34
|
+
function collectInlineBadOps(e, bad) {
|
|
35
|
+
if (!inline_expr_1.INLINE_OPS.has(e.node) && !inline_expr_1.INLINE_LEAVES.has(e.node)) {
|
|
36
|
+
bad.add(e.node);
|
|
37
|
+
}
|
|
38
|
+
if ((0, malloy_types_1.exprHasE)(e)) {
|
|
39
|
+
collectInlineBadOps(e.e, bad);
|
|
40
|
+
}
|
|
41
|
+
else if ((0, malloy_types_1.exprHasKids)(e)) {
|
|
42
|
+
for (const kid of Object.values(e.kids)) {
|
|
43
|
+
if (kid === null)
|
|
44
|
+
continue;
|
|
45
|
+
if (Array.isArray(kid)) {
|
|
46
|
+
for (const k of kid)
|
|
47
|
+
collectInlineBadOps(k, bad);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
collectInlineBadOps(kid, bad);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
23
55
|
class GivenDeclaration extends malloy_element_1.MalloyElement {
|
|
24
|
-
constructor(name, typeDef, defaultExpr) {
|
|
56
|
+
constructor(name, typeDef, defaultExpr, inline = false) {
|
|
25
57
|
super();
|
|
26
58
|
this.name = name;
|
|
27
59
|
this.typeDef = typeDef;
|
|
60
|
+
this.inline = inline;
|
|
28
61
|
this.elementType = 'given';
|
|
29
62
|
this.isNoteableObj = true;
|
|
30
63
|
this.extendNote = noteable_1.extendNoteMethod;
|
|
@@ -44,6 +77,12 @@ class GivenDeclaration extends malloy_element_1.MalloyElement {
|
|
|
44
77
|
this.logError('given-definition-name-conflict', `Cannot redefine '${this.name}'`);
|
|
45
78
|
return;
|
|
46
79
|
}
|
|
80
|
+
// An inline given with no default has nothing to evaluate at bind
|
|
81
|
+
// time. Log and keep going — the given still registers in the
|
|
82
|
+
// namespace so downstream errors don't cascade pointlessly.
|
|
83
|
+
if (this.inline && !this.default) {
|
|
84
|
+
this.logError('inline-no-default', { name: this.name });
|
|
85
|
+
}
|
|
47
86
|
// Default expression. ConstantExpression evaluates through a
|
|
48
87
|
// ConstantFieldSpace that errors on every name lookup, so any
|
|
49
88
|
// non-constant subexpression (field refs, aggregates, etc.) gets
|
|
@@ -112,6 +151,17 @@ class GivenDeclaration extends malloy_element_1.MalloyElement {
|
|
|
112
151
|
}
|
|
113
152
|
givenUsage = closure;
|
|
114
153
|
}
|
|
154
|
+
// Ensure inline expression is resolveable at compile time.
|
|
155
|
+
if (this.inline) {
|
|
156
|
+
const bad = new Set();
|
|
157
|
+
collectInlineBadOps(defaultExpr, bad);
|
|
158
|
+
if (bad.size > 0) {
|
|
159
|
+
this.default.logError('inline-bad-operator', {
|
|
160
|
+
name: this.name,
|
|
161
|
+
operators: [...bad].sort().join(', '),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
115
165
|
}
|
|
116
166
|
}
|
|
117
167
|
const id = (0, source_def_utils_1.mkGivenID)(this.name, (_c = this.location) === null || _c === void 0 ? void 0 : _c.url);
|
|
@@ -124,6 +174,7 @@ class GivenDeclaration extends malloy_element_1.MalloyElement {
|
|
|
124
174
|
givenUsage,
|
|
125
175
|
location: this.location,
|
|
126
176
|
annotation: this.note,
|
|
177
|
+
...(this.inline ? { inline: true } : {}),
|
|
127
178
|
};
|
|
128
179
|
doc.documentGivens.set(id, givenIR);
|
|
129
180
|
const entry = { type: 'given', name: this.name, id };
|
|
@@ -239,10 +239,12 @@ class MalloyElement {
|
|
|
239
239
|
const kiddle = this.children[kidLabel];
|
|
240
240
|
if (kiddle instanceof MalloyElement) {
|
|
241
241
|
yield kiddle;
|
|
242
|
+
yield* kiddle.walk();
|
|
242
243
|
}
|
|
243
244
|
else {
|
|
244
245
|
for (const k of kiddle) {
|
|
245
246
|
yield k;
|
|
247
|
+
yield* k.walk();
|
|
246
248
|
}
|
|
247
249
|
}
|
|
248
250
|
}
|