@malloydata/malloy 0.0.395 → 0.0.396
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/compile.d.ts +7 -6
- package/dist/api/foundation/compile.js +22 -6
- package/dist/api/foundation/runtime.d.ts +85 -5
- package/dist/api/foundation/runtime.js +183 -13
- package/dist/api/foundation/types.d.ts +2 -0
- package/dist/lang/ast/expressions/expr-func.js +30 -11
- package/dist/lang/ast/expressions/expr-given.js +1 -0
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/source-elements/sql-source.js +4 -0
- package/dist/lang/ast/source-elements/table-source.js +4 -0
- package/dist/lang/ast/statements/define-given.d.ts +1 -0
- package/dist/lang/ast/statements/define-given.js +7 -0
- package/dist/lang/ast/statements/import-statement.js +4 -0
- package/dist/lang/ast/types/annotation-elements.d.ts +1 -0
- package/dist/lang/ast/types/annotation-elements.js +10 -3
- package/dist/lang/ast/types/malloy-element.d.ts +1 -0
- package/dist/lang/ast/types/malloy-element.js +4 -0
- package/dist/lang/malloy-to-ast.d.ts +2 -1
- package/dist/lang/malloy-to-ast.js +11 -1
- package/dist/lang/parse-log.d.ts +1 -0
- package/dist/lang/parse-log.js +4 -0
- package/dist/lang/parse-malloy.d.ts +4 -1
- package/dist/lang/parse-malloy.js +26 -4
- package/dist/lang/test/test-translator.d.ts +19 -5
- package/dist/lang/test/test-translator.js +15 -12
- package/dist/lang/zone.d.ts +2 -0
- package/dist/lang/zone.js +10 -0
- package/dist/model/constant_expression_compiler.js +14 -5
- package/dist/model/expression_compiler.js +19 -17
- package/dist/model/field_instance.js +7 -3
- package/dist/model/given_binding.js +26 -21
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.js +3 -1
- package/dist/model/malloy_compile_error.d.ts +13 -0
- package/dist/model/malloy_compile_error.js +23 -0
- package/dist/model/malloy_types.d.ts +2 -0
- package/dist/model/query_model_impl.js +2 -1
- package/dist/model/query_node.d.ts +5 -5
- package/dist/model/query_node.js +21 -16
- package/dist/model/query_query.js +23 -11
- package/dist/model/sql_compiled.js +6 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -41,12 +41,19 @@ class ModelAnnotation extends ObjectAnnotation {
|
|
|
41
41
|
super(...arguments);
|
|
42
42
|
this.elementType = 'modelAnnotation';
|
|
43
43
|
}
|
|
44
|
+
getCompilerFlagNotes() {
|
|
45
|
+
return this.notes.filter(note => note.text.match(COMPILER_FLAG_PREFIX));
|
|
46
|
+
}
|
|
44
47
|
getCompilerFlagLines() {
|
|
45
|
-
return this.
|
|
46
|
-
.filter(note => note.text.match(COMPILER_FLAG_PREFIX))
|
|
47
|
-
.map(note => note.text);
|
|
48
|
+
return this.getCompilerFlagNotes().map(note => note.text);
|
|
48
49
|
}
|
|
49
50
|
execute(doc) {
|
|
51
|
+
if (this.isRestricted()) {
|
|
52
|
+
for (const note of this.getCompilerFlagNotes()) {
|
|
53
|
+
const line = note.text.replace(/\n$/, '');
|
|
54
|
+
this.logError('restricted-construct-forbidden', `\`${line}\` cannot be used in a restricted query — compiler-flag annotations are not permitted.`, { at: note.at });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
50
57
|
if (doc.annotation.notes === undefined) {
|
|
51
58
|
doc.annotation.notes = [];
|
|
52
59
|
}
|
|
@@ -37,6 +37,7 @@ export declare abstract class MalloyElement {
|
|
|
37
37
|
*/
|
|
38
38
|
kupuna(): MalloyElement;
|
|
39
39
|
translator(): MalloyTranslation | undefined;
|
|
40
|
+
isRestricted(): boolean;
|
|
40
41
|
setTranslator(x: MalloyTranslation): void;
|
|
41
42
|
addReference(reference: DocumentReference): void;
|
|
42
43
|
private get sourceURL();
|
|
@@ -158,6 +158,10 @@ class MalloyElement {
|
|
|
158
158
|
}
|
|
159
159
|
return undefined;
|
|
160
160
|
}
|
|
161
|
+
isRestricted() {
|
|
162
|
+
var _a, _b;
|
|
163
|
+
return (_b = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.restrictedMode) !== null && _b !== void 0 ? _b : false;
|
|
164
|
+
}
|
|
161
165
|
setTranslator(x) {
|
|
162
166
|
this.xlate = x;
|
|
163
167
|
}
|
|
@@ -35,10 +35,11 @@ type HasAnnotations = ParserRuleContext & {
|
|
|
35
35
|
export declare class MalloyToAST extends AbstractParseTreeVisitor<ast.MalloyElement> implements MalloyParserVisitor<ast.MalloyElement> {
|
|
36
36
|
readonly parseInfo: MalloyParseInfo;
|
|
37
37
|
readonly msgLog: MessageLogger;
|
|
38
|
+
readonly restrictedMode: boolean;
|
|
38
39
|
readonly timer: Timer;
|
|
39
40
|
private compilerFlagSrc;
|
|
40
41
|
private compilerFlagTag?;
|
|
41
|
-
constructor(parseInfo: MalloyParseInfo, msgLog: MessageLogger, compilerFlagSrc: string[]);
|
|
42
|
+
constructor(parseInfo: MalloyParseInfo, msgLog: MessageLogger, compilerFlagSrc: string[], restrictedMode?: boolean);
|
|
42
43
|
getCompilerFlags(): Tag;
|
|
43
44
|
run(): {
|
|
44
45
|
ast: ast.MalloyElement;
|
|
@@ -92,10 +92,11 @@ const LEGAL_FILTER_TYPES = 'string, number, boolean, date, timestamp, timestampt
|
|
|
92
92
|
* AST from an ANTLR parse tree.
|
|
93
93
|
*/
|
|
94
94
|
class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
|
|
95
|
-
constructor(parseInfo, msgLog, compilerFlagSrc) {
|
|
95
|
+
constructor(parseInfo, msgLog, compilerFlagSrc, restrictedMode = false) {
|
|
96
96
|
super();
|
|
97
97
|
this.parseInfo = parseInfo;
|
|
98
98
|
this.msgLog = msgLog;
|
|
99
|
+
this.restrictedMode = restrictedMode;
|
|
99
100
|
this.timer = new timing_1.Timer('generate_ast');
|
|
100
101
|
const parseCompilerFlagsTimer = new timing_1.Timer('parse_compiler_flags');
|
|
101
102
|
this.compilerFlagSrc = [...DEFAULT_COMPILER_FLAGS, ...compilerFlagSrc];
|
|
@@ -1498,6 +1499,15 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
|
|
|
1498
1499
|
}
|
|
1499
1500
|
updateCompilerFlags(tags) {
|
|
1500
1501
|
const parseCompilerFlagsTimer = new timing_1.Timer('parse_compiler_flags');
|
|
1502
|
+
if (this.restrictedMode) {
|
|
1503
|
+
// `##!` lines in restricted text never become active flags. The
|
|
1504
|
+
// user-facing rejection is logged at execute time (see
|
|
1505
|
+
// ModelAnnotation.execute) so it doesn't short-circuit ASTStep,
|
|
1506
|
+
// which lets every other restricted-mode violation in the same
|
|
1507
|
+
// compile log its own diagnostic.
|
|
1508
|
+
this.timer.contribute([parseCompilerFlagsTimer.stop()]);
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1501
1511
|
const newLines = tags.getCompilerFlagLines();
|
|
1502
1512
|
if (newLines.length > 0) {
|
|
1503
1513
|
const oldLength = this.compilerFlagSrc.length;
|
package/dist/lang/parse-log.d.ts
CHANGED
|
@@ -430,6 +430,7 @@ type MessageParameterTypes = {
|
|
|
430
430
|
'missing-required-group-by': string;
|
|
431
431
|
'invalid-partition-composite': string;
|
|
432
432
|
'integer-literal-out-of-range': string;
|
|
433
|
+
'restricted-construct-forbidden': string;
|
|
433
434
|
};
|
|
434
435
|
export declare const MESSAGE_FORMATTERS: PartialErrorCodeMessageMap;
|
|
435
436
|
export type MessageCode = keyof MessageParameterTypes;
|
package/dist/lang/parse-log.js
CHANGED
|
@@ -101,6 +101,10 @@ exports.MESSAGE_FORMATTERS = {
|
|
|
101
101
|
'inline-no-default': e => `inline given \`${e.name}\` must have a value — there is nothing to inline without one`,
|
|
102
102
|
'inline-bad-operator': e => `inline given \`${e.name}\` uses operator(s) not allowed in inline expressions: ${e.operators}`,
|
|
103
103
|
'invalid-given-modifier': e => `Unknown modifier \`${e.modifier}\` on \`given:\` declaration; the only modifier allowed here is \`inline\``,
|
|
104
|
+
'restricted-construct-forbidden': e => ({
|
|
105
|
+
message: e,
|
|
106
|
+
tag: 'restricted-mode',
|
|
107
|
+
}),
|
|
104
108
|
};
|
|
105
109
|
function makeLogMessage(code, parameters, options) {
|
|
106
110
|
var _a, _b, _c, _d, _e;
|
|
@@ -193,6 +193,7 @@ export declare class MalloyChildTranslator extends MalloyTranslation {
|
|
|
193
193
|
*/
|
|
194
194
|
export declare class MalloyTranslator extends MalloyTranslation {
|
|
195
195
|
private readonly eventStream;
|
|
196
|
+
readonly restrictedMode: boolean;
|
|
196
197
|
schemaZone: Zone<SourceDef>;
|
|
197
198
|
importZone: Zone<string>;
|
|
198
199
|
pretranslatedModels: Map<string, ModelDef>;
|
|
@@ -200,8 +201,10 @@ export declare class MalloyTranslator extends MalloyTranslation {
|
|
|
200
201
|
connectionDialectZone: Zone<string>;
|
|
201
202
|
logger: BaseMessageLogger;
|
|
202
203
|
readonly root: MalloyTranslator;
|
|
203
|
-
constructor(rootURL: string, importURL?: string | null, preload?: ParseUpdate | null, eventStream?: EventStream | null);
|
|
204
|
+
constructor(rootURL: string, importURL?: string | null, preload?: ParseUpdate | null, eventStream?: EventStream | null, restrictedMode?: boolean);
|
|
204
205
|
update(dd: ParseUpdate): void;
|
|
206
|
+
private lockZonesIfRestricted;
|
|
207
|
+
translate(extendingModel?: ModelDef): TranslateResponse;
|
|
205
208
|
logError<T extends MessageCode>(code: T, parameters: MessageParameterType<T>, options?: Omit<LogMessageOptions, 'severity'>): T;
|
|
206
209
|
}
|
|
207
210
|
interface ErrorData {
|
|
@@ -139,6 +139,12 @@ class ImportsAndTablesStep {
|
|
|
139
139
|
if (parseReq.parse === undefined) {
|
|
140
140
|
return parseReq;
|
|
141
141
|
}
|
|
142
|
+
// Every reference this step would register — connection dialects,
|
|
143
|
+
// imports, table schemas — is for a construct that's forbidden in
|
|
144
|
+
// restricted code.
|
|
145
|
+
if (that.root.restrictedMode) {
|
|
146
|
+
return { timingInfo: parseReq.timingInfo };
|
|
147
|
+
}
|
|
142
148
|
if (!this.parseReferences) {
|
|
143
149
|
this.parseReferences = (0, find_external_references_1.findReferences)(that, parseReq.parse.tokenStream, parseReq.parse.root);
|
|
144
150
|
// Register connection dialects and imports immediately. Table
|
|
@@ -278,7 +284,7 @@ class ASTStep {
|
|
|
278
284
|
throw new Error('TRANSLATOR INTERNAL ERROR: Translator parse response had no errors, but also no parser');
|
|
279
285
|
}
|
|
280
286
|
stepTimer.incorporate(parseResponse.timingInfo);
|
|
281
|
-
const secondPass = new malloy_to_ast_1.MalloyToAST(parse, that.root.logger, that.compilerFlagSrc);
|
|
287
|
+
const secondPass = new malloy_to_ast_1.MalloyToAST(parse, that.root.logger, that.compilerFlagSrc, that.root.restrictedMode);
|
|
282
288
|
const { ast: newAST, compilerFlagSrc, timingInfo } = secondPass.run();
|
|
283
289
|
stepTimer.contribute([timingInfo]);
|
|
284
290
|
that.compilerFlagSrc = compilerFlagSrc;
|
|
@@ -466,10 +472,13 @@ class TranslateStep {
|
|
|
466
472
|
modelWasModified: false,
|
|
467
473
|
};
|
|
468
474
|
}
|
|
469
|
-
//
|
|
475
|
+
// Layer the extending model's compiler flags on top of whatever was
|
|
476
|
+
// there already. In production the array starts empty so push vs.
|
|
477
|
+
// overwrite produce the same result; the push lets constructor-time
|
|
478
|
+
// seeding (e.g. TestTranslator's compilerFlags option) survive.
|
|
470
479
|
if (extendingModel && !this.importedAnnotations) {
|
|
471
480
|
const parseCompilerFlagsTimer = new timing_1.Timer('parse_compiler_flags');
|
|
472
|
-
that.compilerFlagSrc
|
|
481
|
+
that.compilerFlagSrc.push(...(0, annotation_1.annotationToTaglines)(extendingModel.annotation, /^##! /));
|
|
473
482
|
stepTimer.contribute([parseCompilerFlagsTimer.stop()]);
|
|
474
483
|
this.importedAnnotations = true;
|
|
475
484
|
}
|
|
@@ -821,9 +830,10 @@ exports.MalloyChildTranslator = MalloyChildTranslator;
|
|
|
821
830
|
* no need to call again, the translation is finished or error'd.
|
|
822
831
|
*/
|
|
823
832
|
class MalloyTranslator extends MalloyTranslation {
|
|
824
|
-
constructor(rootURL, importURL = null, preload = null, eventStream = null) {
|
|
833
|
+
constructor(rootURL, importURL = null, preload = null, eventStream = null, restrictedMode = false) {
|
|
825
834
|
super(rootURL, importURL);
|
|
826
835
|
this.eventStream = eventStream;
|
|
836
|
+
this.restrictedMode = restrictedMode;
|
|
827
837
|
this.schemaZone = new zone_1.Zone();
|
|
828
838
|
this.importZone = new zone_1.Zone();
|
|
829
839
|
this.pretranslatedModels = new Map();
|
|
@@ -845,6 +855,18 @@ class MalloyTranslator extends MalloyTranslation {
|
|
|
845
855
|
this.pretranslatedModels.set(url, dd.translations[url]);
|
|
846
856
|
}
|
|
847
857
|
}
|
|
858
|
+
lockZonesIfRestricted() {
|
|
859
|
+
if (!this.restrictedMode)
|
|
860
|
+
return;
|
|
861
|
+
this.schemaZone.lock();
|
|
862
|
+
this.importZone.lock();
|
|
863
|
+
this.sqlQueryZone.lock();
|
|
864
|
+
this.connectionDialectZone.lock();
|
|
865
|
+
}
|
|
866
|
+
translate(extendingModel) {
|
|
867
|
+
this.lockZonesIfRestricted();
|
|
868
|
+
return super.translate(extendingModel);
|
|
869
|
+
}
|
|
848
870
|
logError(code, parameters, options) {
|
|
849
871
|
this.logger.log((0, parse_log_1.makeLogMessage)(code, parameters, { severity: 'error', ...options }));
|
|
850
872
|
return code;
|
|
@@ -42,12 +42,27 @@ export declare class TestChildTranslator extends MalloyChildTranslator {
|
|
|
42
42
|
translate(): TranslateResponse;
|
|
43
43
|
addChild(url: string): void;
|
|
44
44
|
}
|
|
45
|
+
export interface TestTranslatorOptions {
|
|
46
|
+
rootRule?: string;
|
|
47
|
+
importBaseURL?: string | null;
|
|
48
|
+
eventStream?: EventStream | null;
|
|
49
|
+
internalModel?: ModelDef;
|
|
50
|
+
restrictedMode?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Each entry is a compiler-flag tag fragment — the content that
|
|
53
|
+
* would follow `##! ` in a Malloy source annotation. Rendered to
|
|
54
|
+
* `##! <flag>\n` and pushed onto compilerFlagSrc before any
|
|
55
|
+
* TranslateStep seeding, so the flags are active during AST-build
|
|
56
|
+
* inExperiment() checks.
|
|
57
|
+
*/
|
|
58
|
+
compilerFlags?: string[];
|
|
59
|
+
}
|
|
45
60
|
export declare class TestTranslator extends MalloyTranslator {
|
|
46
61
|
readonly testSrc: string;
|
|
47
62
|
allDialectsEnabled: boolean;
|
|
48
63
|
testRoot?: TestRoot;
|
|
49
64
|
internalModel: ModelDef;
|
|
50
|
-
constructor(testSrc: string,
|
|
65
|
+
constructor(testSrc: string, options?: TestTranslatorOptions);
|
|
51
66
|
translate(): TranslateResponse;
|
|
52
67
|
addChild(url: string): void;
|
|
53
68
|
ast(): MalloyElement | undefined;
|
|
@@ -64,7 +79,7 @@ export declare class TestTranslator extends MalloyTranslator {
|
|
|
64
79
|
export declare class BetaExpression extends TestTranslator {
|
|
65
80
|
readonly sourceName: string;
|
|
66
81
|
private compiled?;
|
|
67
|
-
constructor(src: string, model?: ModelDef, sourceName?: string);
|
|
82
|
+
constructor(src: string, model?: ModelDef, sourceName?: string, options?: Omit<TestTranslatorOptions, 'rootRule' | 'internalModel'>);
|
|
68
83
|
private testFS;
|
|
69
84
|
compile(): void;
|
|
70
85
|
generated(): ExprValue;
|
|
@@ -85,12 +100,11 @@ interface HasTranslator<TT extends TestTranslator> extends MarkedSource {
|
|
|
85
100
|
}
|
|
86
101
|
export declare function expr(unmarked: TemplateStringsArray, ...marked: string[]): HasTranslator<BetaExpression>;
|
|
87
102
|
export declare function model(unmarked: TemplateStringsArray, ...marked: string[]): HasTranslator<TestTranslator>;
|
|
88
|
-
export declare function makeModelFunc(options: {
|
|
89
|
-
model?: ModelDef;
|
|
103
|
+
export declare function makeModelFunc(options: TestTranslatorOptions & {
|
|
90
104
|
prefix?: string;
|
|
91
105
|
wrap?: (code: string) => string;
|
|
92
106
|
}): (unmarked: TemplateStringsArray, ...marked: string[]) => HasTranslator<TestTranslator>;
|
|
93
|
-
export declare function makeExprFunc(model
|
|
107
|
+
export declare function makeExprFunc(model?: ModelDef, sourceName?: string, options?: Omit<TestTranslatorOptions, 'rootRule' | 'internalModel'>): (unmarked: TemplateStringsArray, ...marked: string[]) => HasTranslator<TestTranslator>;
|
|
94
108
|
export declare function markSource(unmarked: TemplateStringsArray, ...marked: string[]): MarkedSource;
|
|
95
109
|
export declare function getSelectOneStruct(sqlBlock: SQLSourceRequest): {
|
|
96
110
|
[key: string]: SQLSourceDef;
|
|
@@ -330,8 +330,9 @@ class TestChildTranslator extends parse_malloy_1.MalloyChildTranslator {
|
|
|
330
330
|
exports.TestChildTranslator = TestChildTranslator;
|
|
331
331
|
const testURI = 'internal://test/langtests/root.malloy';
|
|
332
332
|
class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
333
|
-
constructor(testSrc,
|
|
334
|
-
|
|
333
|
+
constructor(testSrc, options = {}) {
|
|
334
|
+
var _a, _b, _c, _d, _e;
|
|
335
|
+
super(testURI, (_a = options.importBaseURL) !== null && _a !== void 0 ? _a : null, null, (_b = options.eventStream) !== null && _b !== void 0 ? _b : null, (_c = options.restrictedMode) !== null && _c !== void 0 ? _c : false);
|
|
335
336
|
this.testSrc = testSrc;
|
|
336
337
|
this.allDialectsEnabled = true;
|
|
337
338
|
/*
|
|
@@ -415,16 +416,19 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
|
415
416
|
},
|
|
416
417
|
},
|
|
417
418
|
};
|
|
418
|
-
this.grammarRule = rootRule;
|
|
419
|
+
this.grammarRule = (_d = options.rootRule) !== null && _d !== void 0 ? _d : 'malloyDocument';
|
|
419
420
|
this.importZone.define(testURI, testSrc);
|
|
420
|
-
if (internalModel !== undefined) {
|
|
421
|
-
this.internalModel = internalModel;
|
|
421
|
+
if (options.internalModel !== undefined) {
|
|
422
|
+
this.internalModel = options.internalModel;
|
|
422
423
|
}
|
|
423
424
|
for (const actualSchema of exports.mockSchema) {
|
|
424
425
|
this.schemaZone.define(`${actualSchema.connection}:${actualSchema.tablePath}`, actualSchema);
|
|
425
426
|
}
|
|
426
427
|
this.connectionDialectZone.define('_db_', exports.TEST_DIALECT);
|
|
427
428
|
this.connectionDialectZone.define('_bq_', 'standardsql');
|
|
429
|
+
for (const flag of (_e = options.compilerFlags) !== null && _e !== void 0 ? _e : []) {
|
|
430
|
+
this.compilerFlagSrc.push(`##! ${flag}\n`);
|
|
431
|
+
}
|
|
428
432
|
}
|
|
429
433
|
translate() {
|
|
430
434
|
return super.translate(this.internalModel);
|
|
@@ -532,8 +536,8 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
|
532
536
|
exports.TestTranslator = TestTranslator;
|
|
533
537
|
TestTranslator.inspectCompile = false;
|
|
534
538
|
class BetaExpression extends TestTranslator {
|
|
535
|
-
constructor(src, model, sourceName = 'ab') {
|
|
536
|
-
super(src,
|
|
539
|
+
constructor(src, model, sourceName = 'ab', options = {}) {
|
|
540
|
+
super(src, { ...options, rootRule: 'debugExpr', internalModel: model });
|
|
537
541
|
this.sourceName = sourceName;
|
|
538
542
|
}
|
|
539
543
|
testFS() {
|
|
@@ -627,21 +631,20 @@ function model(unmarked, ...marked) {
|
|
|
627
631
|
}
|
|
628
632
|
function makeModelFunc(options) {
|
|
629
633
|
return function model(unmarked, ...marked) {
|
|
630
|
-
var _a;
|
|
631
634
|
const ms = markSource(unmarked, ...marked);
|
|
635
|
+
const { prefix, wrap, ...ttOptions } = options;
|
|
632
636
|
return {
|
|
633
637
|
...ms,
|
|
634
|
-
translator: new TestTranslator((
|
|
635
|
-
(options.wrap ? options.wrap(ms.code) : ms.code), null, null, undefined, options === null || options === void 0 ? void 0 : options.model),
|
|
638
|
+
translator: new TestTranslator((prefix !== null && prefix !== void 0 ? prefix : '') + (wrap ? wrap(ms.code) : ms.code), ttOptions),
|
|
636
639
|
};
|
|
637
640
|
};
|
|
638
641
|
}
|
|
639
|
-
function makeExprFunc(model, sourceName) {
|
|
642
|
+
function makeExprFunc(model, sourceName = 'ab', options = {}) {
|
|
640
643
|
return function expr(unmarked, ...marked) {
|
|
641
644
|
const ms = markSource(unmarked, ...marked);
|
|
642
645
|
return {
|
|
643
646
|
...ms,
|
|
644
|
-
translator: new BetaExpression(ms.code, model, sourceName),
|
|
647
|
+
translator: new BetaExpression(ms.code, model, sourceName, options),
|
|
645
648
|
};
|
|
646
649
|
};
|
|
647
650
|
}
|
package/dist/lang/zone.d.ts
CHANGED
|
@@ -28,7 +28,9 @@ export type ZoneEntry<T> = EntryPresent<T> | ReferenceEntry | EntryErrored;
|
|
|
28
28
|
export declare class Zone<TValue> {
|
|
29
29
|
zone: Map<string, ZoneEntry<TValue>>;
|
|
30
30
|
location: Record<string, DocumentLocation>;
|
|
31
|
+
private locked;
|
|
31
32
|
constructor();
|
|
33
|
+
lock(): void;
|
|
32
34
|
get(str: string): TValue | undefined;
|
|
33
35
|
getEntry(str: string): ZoneEntry<TValue>;
|
|
34
36
|
/**
|
package/dist/lang/zone.js
CHANGED
|
@@ -33,8 +33,12 @@ exports.Zone = void 0;
|
|
|
33
33
|
class Zone {
|
|
34
34
|
constructor() {
|
|
35
35
|
this.location = {};
|
|
36
|
+
this.locked = false;
|
|
36
37
|
this.zone = new Map();
|
|
37
38
|
}
|
|
39
|
+
lock() {
|
|
40
|
+
this.locked = true;
|
|
41
|
+
}
|
|
38
42
|
get(str) {
|
|
39
43
|
const zst = this.zone.get(str);
|
|
40
44
|
if ((zst === null || zst === void 0 ? void 0 : zst.status) === 'present') {
|
|
@@ -57,6 +61,8 @@ class Zone {
|
|
|
57
61
|
* @param val
|
|
58
62
|
*/
|
|
59
63
|
define(str, val) {
|
|
64
|
+
if (this.locked)
|
|
65
|
+
return;
|
|
60
66
|
this.zone.set(str, { status: 'present', value: val });
|
|
61
67
|
}
|
|
62
68
|
/**
|
|
@@ -65,6 +71,8 @@ class Zone {
|
|
|
65
71
|
* @param loc The location of the reference
|
|
66
72
|
*/
|
|
67
73
|
reference(str, loc) {
|
|
74
|
+
if (this.locked)
|
|
75
|
+
return;
|
|
68
76
|
const zst = this.zone.get(str);
|
|
69
77
|
if ((zst === null || zst === void 0 ? void 0 : zst.status) === undefined) {
|
|
70
78
|
this.zone.set(str, { status: 'reference', firstReference: loc });
|
|
@@ -89,6 +97,8 @@ class Zone {
|
|
|
89
97
|
* @param errorData Pass on errors encountered during fetch
|
|
90
98
|
*/
|
|
91
99
|
updateFrom(updateData, errorData) {
|
|
100
|
+
if (this.locked)
|
|
101
|
+
return;
|
|
92
102
|
if (updateData) {
|
|
93
103
|
for (const [updateKey, updateVal] of Object.entries(updateData)) {
|
|
94
104
|
if (updateVal !== undefined) {
|
|
@@ -14,11 +14,20 @@ const field_instance_1 = require("./field_instance");
|
|
|
14
14
|
* Used to distinguish expected errors from unexpected ones.
|
|
15
15
|
*/
|
|
16
16
|
class ConstantExpressionError extends Error {
|
|
17
|
-
constructor(message) {
|
|
17
|
+
constructor(message, at) {
|
|
18
18
|
super(message);
|
|
19
|
+
this.at = at;
|
|
19
20
|
this.name = 'ConstantExpressionError';
|
|
20
21
|
}
|
|
21
22
|
}
|
|
23
|
+
function locSuffix(at) {
|
|
24
|
+
if (!at)
|
|
25
|
+
return '';
|
|
26
|
+
// Display 1-based line/column; range positions are 0-based.
|
|
27
|
+
const line = at.range.start.line + 1;
|
|
28
|
+
const col = at.range.start.character + 1;
|
|
29
|
+
return ` at ${at.url}:${line}:${col}`;
|
|
30
|
+
}
|
|
22
31
|
/**
|
|
23
32
|
* Minimal FieldInstanceResultRoot for constant expressions.
|
|
24
33
|
* This serves as both the result set and its own root, providing
|
|
@@ -106,11 +115,11 @@ class ConstantQueryStruct extends query_node_1.QueryStruct {
|
|
|
106
115
|
/**
|
|
107
116
|
* These methods should not be called for constant expressions
|
|
108
117
|
*/
|
|
109
|
-
getFieldByName(path) {
|
|
110
|
-
throw new ConstantExpressionError(`Illegal reference to '${path.join('.')}' in constant expressions
|
|
118
|
+
getFieldByName(path, at) {
|
|
119
|
+
throw new ConstantExpressionError(`Illegal reference to '${path.join('.')}' in constant expressions${locSuffix(at)}`, at);
|
|
111
120
|
}
|
|
112
|
-
getStructByName(path) {
|
|
113
|
-
throw new ConstantExpressionError(`Illegal reference to '${path.join('.')}' in constant expressions
|
|
121
|
+
getStructByName(path, at) {
|
|
122
|
+
throw new ConstantExpressionError(`Illegal reference to '${path.join('.')}' in constant expressions${locSuffix(at)}`, at);
|
|
114
123
|
}
|
|
115
124
|
getSQLIdentifier() {
|
|
116
125
|
throw new ConstantExpressionError('Constant expressions do not need SQL identifiers');
|
|
@@ -29,6 +29,7 @@ const field_instance_1 = require("./field_instance");
|
|
|
29
29
|
const filter_compilers_1 = require("./filter_compilers");
|
|
30
30
|
const utils_1 = require("./utils");
|
|
31
31
|
const query_node_1 = require("./query_node");
|
|
32
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
32
33
|
const NUMERIC_DECIMAL_PRECISION = 9;
|
|
33
34
|
function sqlSumDistinct(dialect, sqlExp, sqlDistintKey) {
|
|
34
35
|
const precision = 9;
|
|
@@ -186,7 +187,7 @@ function compileExpr(resultSet, context, expr, state = new utils_1.GenerateState
|
|
|
186
187
|
return `${expr.kids.e.sql} ${expr.not ? 'NOT IN' : 'IN'} (${oneOf})`;
|
|
187
188
|
}
|
|
188
189
|
case 'inGiven': {
|
|
189
|
-
const bound = resolveGivenBoundExpr(context, expr.givenRef
|
|
190
|
+
const bound = resolveGivenBoundExpr(context, expr.givenRef);
|
|
190
191
|
// null binding collapses to empty-set semantics — not the SQL
|
|
191
192
|
// `IN (NULL)` shape, which has confusing NULL-membership rules.
|
|
192
193
|
if (bound.node === 'null') {
|
|
@@ -280,27 +281,27 @@ function generateAppliedFilter(context, filterMatchExpr, qi) {
|
|
|
280
281
|
filterExpr = argument.value;
|
|
281
282
|
}
|
|
282
283
|
else {
|
|
283
|
-
throw new
|
|
284
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Parameter '${name}' has no value, but a filter expression is required here.`, 'compiler-filter-parameter-no-value', filterExpr.at);
|
|
284
285
|
}
|
|
285
286
|
}
|
|
286
287
|
if (filterExpr.node === 'given') {
|
|
287
|
-
const
|
|
288
|
-
const supplied = (_c = (_b = context.prepareResultOptions) === null || _b === void 0 ? void 0 : _b.resolvedGivens) === null || _c === void 0 ? void 0 : _c.get(id);
|
|
288
|
+
const supplied = (_c = (_b = context.prepareResultOptions) === null || _b === void 0 ? void 0 : _b.resolvedGivens) === null || _c === void 0 ? void 0 : _c.get(filterExpr.id);
|
|
289
289
|
if (supplied !== undefined) {
|
|
290
290
|
filterExpr = supplied;
|
|
291
291
|
}
|
|
292
292
|
else {
|
|
293
|
-
const decl = context.getModel().givens[id];
|
|
293
|
+
const decl = context.getModel().givens[filterExpr.id];
|
|
294
294
|
if ((decl === null || decl === void 0 ? void 0 : decl.default) !== undefined) {
|
|
295
295
|
filterExpr = decl.default;
|
|
296
296
|
}
|
|
297
297
|
else {
|
|
298
|
-
throw new
|
|
298
|
+
throw new malloy_compile_error_1.MalloyCompileError(unsatisfiedGivenMessage(filterExpr.refName), 'compiler-given-no-value', filterExpr.at);
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
if (filterExpr.node !== 'filterLiteral') {
|
|
303
|
-
throw new
|
|
303
|
+
throw new malloy_compile_error_1.MalloyCompileError("Filter context requires a filter-expression literal (e.g., `f'...'`) " +
|
|
304
|
+
`or a parameter that resolves to one; got node '${filterExpr.node}'.`, 'compiler-filter-not-literal', undefined);
|
|
304
305
|
}
|
|
305
306
|
const filterSrc = filterExpr.filterSrc;
|
|
306
307
|
let fParse;
|
|
@@ -320,10 +321,11 @@ function generateAppliedFilter(context, filterMatchExpr, qi) {
|
|
|
320
321
|
fParse = malloy_filter_1.TemporalFilterExpression.parse(filterSrc);
|
|
321
322
|
break;
|
|
322
323
|
default:
|
|
323
|
-
throw new
|
|
324
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Filter type '${filterMatchExpr.dataType}' is not supported. ` +
|
|
325
|
+
'Supported filter types: string, number, boolean, date, timestamp, timestamptz.', 'compiler-filter-type-unsupported', undefined);
|
|
324
326
|
}
|
|
325
327
|
if (fParse.log.length > 0) {
|
|
326
|
-
throw new
|
|
328
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Filter expression parse error: ${fParse.log[0]}.`, 'compiler-filter-parse-error', undefined);
|
|
327
329
|
}
|
|
328
330
|
return filter_compilers_1.FilterCompilers.compile(filterMatchExpr.dataType, fParse.parsed, filterMatchExpr.kids.expr.sql || '', context.dialect, qi);
|
|
329
331
|
}
|
|
@@ -581,7 +583,7 @@ function generateFunctionCallExpression(resultSet, context, frag, state) {
|
|
|
581
583
|
}
|
|
582
584
|
function generateFieldFragment(resultSet, context, expr, state) {
|
|
583
585
|
// find the structDef and return the path to the field...
|
|
584
|
-
const fieldRef = context.getFieldByName(expr.path);
|
|
586
|
+
const fieldRef = context.getFieldByName(expr.path, expr.at);
|
|
585
587
|
if ((0, malloy_types_1.hasExpression)(fieldRef.fieldDef)) {
|
|
586
588
|
const ret = exprToSQL(resultSet, fieldRef.parent, fieldRef.fieldDef.e, state);
|
|
587
589
|
return `(${ret})`;
|
|
@@ -614,7 +616,7 @@ function generateParameterFragment(resultSet, context, expr, state) {
|
|
|
614
616
|
if (argument === null || argument === void 0 ? void 0 : argument.value) {
|
|
615
617
|
return exprToSQL(resultSet, context, argument.value, state);
|
|
616
618
|
}
|
|
617
|
-
throw new
|
|
619
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Parameter '${expr.path.join('.')}' has no value supplied.`, 'compiler-parameter-no-value', expr.at);
|
|
618
620
|
}
|
|
619
621
|
/**
|
|
620
622
|
* Resolve a given to the Expr that should stand in for it at SQL emit:
|
|
@@ -625,20 +627,20 @@ function generateParameterFragment(resultSet, context, expr, state) {
|
|
|
625
627
|
* Shared by `generateGivenFragment` ($NAME directly in an expression)
|
|
626
628
|
* and the `'inGiven'` SQL-emit case ($ARR in `expr in $ARR`).
|
|
627
629
|
*/
|
|
628
|
-
function resolveGivenBoundExpr(context,
|
|
630
|
+
function resolveGivenBoundExpr(context, ref) {
|
|
629
631
|
var _a, _b;
|
|
630
|
-
const supplied = (_b = (_a = context.prepareResultOptions) === null || _a === void 0 ? void 0 : _a.resolvedGivens) === null || _b === void 0 ? void 0 : _b.get(id);
|
|
632
|
+
const supplied = (_b = (_a = context.prepareResultOptions) === null || _a === void 0 ? void 0 : _a.resolvedGivens) === null || _b === void 0 ? void 0 : _b.get(ref.id);
|
|
631
633
|
if (supplied !== undefined)
|
|
632
634
|
return supplied;
|
|
633
|
-
const decl = context.getModel().givens[id];
|
|
635
|
+
const decl = context.getModel().givens[ref.id];
|
|
634
636
|
if ((decl === null || decl === void 0 ? void 0 : decl.default) !== undefined)
|
|
635
637
|
return decl.default;
|
|
636
|
-
throw new
|
|
638
|
+
throw new malloy_compile_error_1.MalloyCompileError(unsatisfiedGivenMessage(ref.refName), 'compiler-given-no-value', ref.at);
|
|
637
639
|
}
|
|
638
640
|
function generateGivenFragment(resultSet, context, expr, state) {
|
|
639
641
|
// The bound expr may itself be a `$OTHER`-bearing expression; recursive
|
|
640
642
|
// compile handles default chains.
|
|
641
|
-
const bound = resolveGivenBoundExpr(context, expr
|
|
643
|
+
const bound = resolveGivenBoundExpr(context, expr);
|
|
642
644
|
return exprToSQL(resultSet, context, bound, state);
|
|
643
645
|
}
|
|
644
646
|
function unsatisfiedGivenMessage(refName) {
|
|
@@ -663,7 +665,7 @@ function generateDimFragment(resultSet, context, expr, state) {
|
|
|
663
665
|
}
|
|
664
666
|
function generateUngroupedFragment(resultSet, context, expr, state) {
|
|
665
667
|
if (state.totalGroupSet !== -1) {
|
|
666
|
-
throw new
|
|
668
|
+
throw new malloy_compile_error_1.MalloyCompileError("Cannot nest 'all()' or 'exclude()' inside another 'all()' calculation.", 'compiler-nested-ungroup', undefined);
|
|
667
669
|
}
|
|
668
670
|
let totalGroupSet;
|
|
669
671
|
let ungroupSet;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.FieldInstanceResultRoot = exports.FieldInstanceResult = exports.FieldInstanceField = void 0;
|
|
8
8
|
exports.sqlFullChildReference = sqlFullChildReference;
|
|
9
|
+
const malloy_compile_error_1 = require("./malloy_compile_error");
|
|
9
10
|
const malloy_types_1 = require("./malloy_types");
|
|
10
11
|
const utils_1 = require("./utils");
|
|
11
12
|
const join_instance_1 = require("./join_instance");
|
|
@@ -139,7 +140,8 @@ class FieldInstanceResult {
|
|
|
139
140
|
const fi = this.allFields.get(as);
|
|
140
141
|
if (fi) {
|
|
141
142
|
if (fi.type === 'query') {
|
|
142
|
-
throw new
|
|
143
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Field '${field.fieldDef.name}' is already defined as a nested view; ` +
|
|
144
|
+
'cannot also use it as a scalar field in this output.', 'compiler-field-redefined-as-struct', field.fieldDef.location);
|
|
143
145
|
}
|
|
144
146
|
const fif = fi;
|
|
145
147
|
if (fif.fieldUsage.type === 'result') {
|
|
@@ -148,7 +150,8 @@ class FieldInstanceResult {
|
|
|
148
150
|
return;
|
|
149
151
|
}
|
|
150
152
|
else {
|
|
151
|
-
throw new
|
|
153
|
+
throw new malloy_compile_error_1.MalloyCompileError(`Output field name '${field.fieldDef.name}' is ambiguous — ` +
|
|
154
|
+
'defined more than once at the query output level.', 'compiler-ambiguous-output-name', field.fieldDef.location);
|
|
152
155
|
}
|
|
153
156
|
}
|
|
154
157
|
}
|
|
@@ -373,7 +376,8 @@ class FieldInstanceResult {
|
|
|
373
376
|
// verify that all names specified are available in the current scope.
|
|
374
377
|
for (const fieldName of (ungroupSet === null || ungroupSet === void 0 ? void 0 : ungroupSet.fields) || []) {
|
|
375
378
|
if (inScopeFieldNames.indexOf(fieldName) === -1) {
|
|
376
|
-
throw new
|
|
379
|
+
throw new malloy_compile_error_1.MalloyCompileError(`'${ungroupSet === null || ungroupSet === void 0 ? void 0 : ungroupSet.type}()' references field '${fieldName}', ` +
|
|
380
|
+
'which is not defined or not in scope at this nesting level.', 'compiler-ungroup-field-unknown', undefined);
|
|
377
381
|
}
|
|
378
382
|
}
|
|
379
383
|
return ret;
|