@malloydata/malloy 0.0.435 → 0.0.436
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/build_targets.d.ts +5 -6
- package/dist/api/foundation/build_targets.js +74 -6
- package/dist/api/foundation/core.d.ts +16 -4
- package/dist/api/foundation/core.js +23 -23
- package/dist/api/foundation/index.d.ts +1 -1
- package/dist/api/foundation/runtime.d.ts +21 -2
- package/dist/api/foundation/runtime.js +44 -31
- package/dist/api/foundation/types.d.ts +43 -3
- package/dist/connection/dbmeta.d.ts +29 -0
- package/dist/connection/dbmeta.js +46 -0
- package/dist/connection/index.d.ts +1 -0
- package/dist/connection/index.js +1 -0
- package/dist/dialect/databricks/databricks.d.ts +11 -12
- package/dist/dialect/databricks/databricks.js +24 -36
- package/dist/dialect/dialect.d.ts +56 -170
- package/dist/dialect/dialect.js +89 -90
- package/dist/dialect/duckdb/duckdb.d.ts +2 -2
- package/dist/dialect/duckdb/duckdb.js +1 -1
- package/dist/dialect/index.d.ts +1 -1
- package/dist/dialect/index.js +2 -2
- package/dist/dialect/mysql/mysql.d.ts +11 -12
- package/dist/dialect/mysql/mysql.js +20 -32
- package/dist/dialect/pg_impl.d.ts +9 -10
- package/dist/dialect/pg_impl.js +27 -73
- package/dist/dialect/postgres/postgres.d.ts +4 -4
- package/dist/dialect/postgres/postgres.js +4 -12
- package/dist/dialect/snowflake/snowflake.d.ts +11 -13
- package/dist/dialect/snowflake/snowflake.js +30 -82
- package/dist/dialect/sqlserver/sqlserver.d.ts +12 -13
- package/dist/dialect/sqlserver/sqlserver.js +46 -47
- package/dist/dialect/standardsql/standardsql.d.ts +11 -16
- package/dist/dialect/standardsql/standardsql.js +22 -73
- package/dist/dialect/trino/trino.d.ts +16 -18
- package/dist/dialect/trino/trino.js +127 -181
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lang/ast/expressions/boolean-value.d.ts +24 -0
- package/dist/lang/ast/expressions/boolean-value.js +41 -0
- package/dist/lang/ast/expressions/case.js +7 -0
- package/dist/lang/ast/expressions/expr-alternation-tree.js +11 -0
- package/dist/lang/ast/expressions/expr-cast.js +5 -0
- package/dist/lang/ast/expressions/expr-coalesce.js +4 -0
- package/dist/lang/ast/expressions/expr-func.js +13 -2
- package/dist/lang/ast/expressions/expr-minus.js +5 -2
- package/dist/lang/ast/expressions/expr-null.js +4 -0
- package/dist/lang/ast/expressions/pick-when.js +7 -0
- package/dist/lang/ast/field-space/index-field-space.js +13 -1
- package/dist/lang/ast/field-space/query-spaces.js +11 -0
- package/dist/lang/ast/query-builders/reduce-builder.js +1 -1
- package/dist/lang/ast/query-items/field-declaration.d.ts +5 -0
- package/dist/lang/ast/query-items/field-declaration.js +22 -16
- package/dist/lang/ast/query-items/field-references.d.ts +6 -0
- package/dist/lang/ast/query-items/field-references.js +23 -0
- package/dist/lang/ast/query-properties/filters.js +3 -1
- package/dist/lang/ast/statements/import-statement.js +13 -0
- package/dist/lang/ast/types/expression-def.js +17 -2
- package/dist/lang/ast/types/malloy-element.d.ts +24 -1
- package/dist/lang/ast/types/malloy-element.js +63 -26
- package/dist/lang/ast/view-elements/reference-view.js +4 -0
- package/dist/lang/ast/view-elements/refine-utils.js +1 -0
- package/dist/lang/composite-source-utils.js +10 -17
- package/dist/lang/parse-log.d.ts +12 -0
- package/dist/lang/parse-log.js +2 -0
- package/dist/lang/test/test-translator.d.ts +2 -1
- package/dist/lang/test/test-translator.js +37 -3
- package/dist/model/expression_compiler.js +8 -7
- package/dist/model/filter_compilers.js +13 -12
- package/dist/model/given_binding.d.ts +8 -0
- package/dist/model/given_binding.js +13 -0
- package/dist/model/index.d.ts +1 -1
- package/dist/model/index.js +2 -1
- package/dist/model/sql_compiled.d.ts +19 -20
- package/dist/model/sql_compiled.js +29 -17
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -38,7 +38,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
})();
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.ExprMinus = void 0;
|
|
41
|
-
const ast_utils_1 = require("../ast-utils");
|
|
42
41
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
43
42
|
const expression_def_1 = require("../types/expression-def");
|
|
44
43
|
class ExprMinus extends expression_def_1.ExpressionDef {
|
|
@@ -50,6 +49,10 @@ class ExprMinus extends expression_def_1.ExpressionDef {
|
|
|
50
49
|
}
|
|
51
50
|
computeExpression(fs) {
|
|
52
51
|
const expr = this.expr.getExpression(fs);
|
|
52
|
+
// An error is already logged; it stays an error so nothing else logs it
|
|
53
|
+
if (expr.type === 'error') {
|
|
54
|
+
return expr;
|
|
55
|
+
}
|
|
53
56
|
if (TDU.typeIn(expr, this.legalChildTypes)) {
|
|
54
57
|
return {
|
|
55
58
|
...expr,
|
|
@@ -57,7 +60,7 @@ class ExprMinus extends expression_def_1.ExpressionDef {
|
|
|
57
60
|
value: { node: 'unary-', e: expr.value },
|
|
58
61
|
};
|
|
59
62
|
}
|
|
60
|
-
return (
|
|
63
|
+
return this.expr.loggedErrorExpr('expression-type-error', `'${this.elementType}' Can't use type ${TDU.inspect(expr)}`);
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
exports.ExprMinus = ExprMinus;
|
|
@@ -7,11 +7,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.ExprIsNull = exports.PartialIsNull = exports.ExprNULL = void 0;
|
|
8
8
|
const expr_value_1 = require("../types/expr-value");
|
|
9
9
|
const expression_def_1 = require("../types/expression-def");
|
|
10
|
+
const boolean_value_1 = require("./boolean-value");
|
|
10
11
|
function doIsNull(fs, op, expr) {
|
|
11
12
|
// Build a new value rather than retyping the operand's in place: what
|
|
12
13
|
// getExpression hands back is shared, and the operand is usually asked for
|
|
13
14
|
// its value again after this.
|
|
14
15
|
const nullCmp = expr.getExpression(fs);
|
|
16
|
+
const noTest = (0, boolean_value_1.booleanValueError)(fs, nullCmp, 'in a null test', expr, boolean_value_1.CONDITION_HINT);
|
|
17
|
+
if (noTest)
|
|
18
|
+
return noTest;
|
|
15
19
|
return (0, expr_value_1.computedExprValue)({
|
|
16
20
|
dataType: { type: 'boolean' },
|
|
17
21
|
value: {
|
|
@@ -42,6 +42,7 @@ const TDU = __importStar(require("../typedesc-utils"));
|
|
|
42
42
|
const expr_value_1 = require("../types/expr-value");
|
|
43
43
|
const expression_def_1 = require("../types/expression-def");
|
|
44
44
|
const malloy_element_1 = require("../types/malloy-element");
|
|
45
|
+
const boolean_value_1 = require("./boolean-value");
|
|
45
46
|
function typeCoalesce(ev1, ev2) {
|
|
46
47
|
if (ev1 === undefined || ev1.type === 'null' || ev1.type === 'error') {
|
|
47
48
|
return ev2;
|
|
@@ -131,6 +132,9 @@ class Pick extends expression_def_1.ExpressionDef {
|
|
|
131
132
|
if (definedReturnType.type === 'filter expression') {
|
|
132
133
|
return this.loggedErrorExpr('filter-expression-error', 'Pick statments cannot have filter expression values');
|
|
133
134
|
}
|
|
135
|
+
const noPick = (0, boolean_value_1.booleanValueError)(fs, definedReturnType, 'as the result of a pick', this, boolean_value_1.CHOICE_HINT);
|
|
136
|
+
if (noPick)
|
|
137
|
+
return noPick;
|
|
134
138
|
caseValue.kids.caseElse = defaultVal.value;
|
|
135
139
|
return (0, expr_value_1.computedExprValue)({
|
|
136
140
|
dataType: definedReturnType,
|
|
@@ -193,6 +197,9 @@ class Pick extends expression_def_1.ExpressionDef {
|
|
|
193
197
|
if (definedReturnType.type === 'filter expression') {
|
|
194
198
|
return this.loggedErrorExpr('filter-expression-error', 'Pick statments cannot have filter expression values');
|
|
195
199
|
}
|
|
200
|
+
const noPick = (0, boolean_value_1.booleanValueError)(fs, definedReturnType, 'as the result of a pick', this, boolean_value_1.CHOICE_HINT);
|
|
201
|
+
if (noPick)
|
|
202
|
+
return noPick;
|
|
196
203
|
pick.kids.caseElse = defVal.value;
|
|
197
204
|
return (0, expr_value_1.computedExprValue)({
|
|
198
205
|
dataType: definedReturnType,
|
|
@@ -8,6 +8,7 @@ exports.IndexFieldSpace = void 0;
|
|
|
8
8
|
const composite_source_utils_1 = require("../../composite-source-utils");
|
|
9
9
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
10
10
|
const error_factory_1 = require("../error-factory");
|
|
11
|
+
const boolean_value_1 = require("../expressions/boolean-value");
|
|
11
12
|
const field_references_1 = require("../query-items/field-references");
|
|
12
13
|
const space_field_1 = require("../types/space-field");
|
|
13
14
|
const query_spaces_1 = require("./query-spaces");
|
|
@@ -98,10 +99,21 @@ class IndexFieldSpace extends query_spaces_1.QueryOperationSpace {
|
|
|
98
99
|
}
|
|
99
100
|
else {
|
|
100
101
|
const eTypeDesc = entry.typeDesc();
|
|
102
|
+
if (
|
|
101
103
|
// Don't index arrays and records
|
|
102
|
-
|
|
104
|
+
malloy_types_1.TD.isBasicAtomic(eTypeDesc) &&
|
|
103
105
|
(0, malloy_types_1.expressionIsScalar)(eTypeDesc.expressionType) &&
|
|
104
106
|
(dialect === undefined || !dialect.ignoreInProject(name))) {
|
|
107
|
+
if (eTypeDesc.type === 'boolean' && (dialect === null || dialect === void 0 ? void 0 : dialect.booleanType) === 'none') {
|
|
108
|
+
const path = [...joinPath, name].join('.');
|
|
109
|
+
wild.logWarning('wildcard-omits-boolean', {
|
|
110
|
+
dialect: dialect.name,
|
|
111
|
+
wildcard: wild.refString,
|
|
112
|
+
name: path,
|
|
113
|
+
hint: (0, boolean_value_1.resultColumnHint)(path),
|
|
114
|
+
});
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
105
117
|
expandEntries.push({ name: indexName, entry });
|
|
106
118
|
this.expandedWild.set(indexName, {
|
|
107
119
|
path: joinPath.concat(name),
|
|
@@ -48,6 +48,7 @@ const static_space_1 = require("./static-space");
|
|
|
48
48
|
const query_input_space_1 = require("./query-input-space");
|
|
49
49
|
const composite_source_utils_1 = require("../../composite-source-utils");
|
|
50
50
|
const error_factory_1 = require("../error-factory");
|
|
51
|
+
const boolean_value_1 = require("../expressions/boolean-value");
|
|
51
52
|
const reference_field_1 = require("./reference-field");
|
|
52
53
|
const refine_from_space_field_1 = require("./refine-from-space-field");
|
|
53
54
|
/**
|
|
@@ -158,6 +159,16 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
|
|
|
158
159
|
if (model.TD.isAtomic(eType) &&
|
|
159
160
|
model.expressionIsScalar(eType.expressionType) &&
|
|
160
161
|
(dialect === undefined || !dialect.ignoreInProject(name))) {
|
|
162
|
+
if (eType.type === 'boolean' && (dialect === null || dialect === void 0 ? void 0 : dialect.booleanType) === 'none') {
|
|
163
|
+
const path = joinPath.concat(name).join('.');
|
|
164
|
+
wild.logWarning('wildcard-omits-boolean', {
|
|
165
|
+
dialect: dialect.name,
|
|
166
|
+
wildcard: wild.refString,
|
|
167
|
+
name: path,
|
|
168
|
+
hint: (0, boolean_value_1.resultColumnHint)(path),
|
|
169
|
+
});
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
161
172
|
expandEntries.push({ name, entry });
|
|
162
173
|
this.expandedWild.set(name, {
|
|
163
174
|
path: joinPath.concat(name),
|
|
@@ -55,7 +55,7 @@ class QuerySegmentBuilder {
|
|
|
55
55
|
}
|
|
56
56
|
refineFrom(from, to) {
|
|
57
57
|
if (from && from.type !== 'index' && from.type !== 'raw') {
|
|
58
|
-
if (!this.
|
|
58
|
+
if (!this.order && from.orderBy && !from.defaultOrderBy) {
|
|
59
59
|
to.orderBy = from.orderBy;
|
|
60
60
|
}
|
|
61
61
|
if (!this.limit && from.limit) {
|
|
@@ -19,24 +19,29 @@ export declare abstract class AtomicFieldDeclaration extends MalloyElement imple
|
|
|
19
19
|
fieldDef(fs: FieldSpace, exprName: string): FieldDef;
|
|
20
20
|
abstract typecheckExprValue(expr: ExprValue): void;
|
|
21
21
|
executesInOutputSpace(): boolean;
|
|
22
|
+
outputsValue(): boolean;
|
|
22
23
|
queryFieldDef(exprFS: FieldSpace, exprName: string): AtomicFieldDef;
|
|
23
24
|
makeEntry(fs: DynamicSpace): void;
|
|
24
25
|
}
|
|
25
26
|
export declare class CalculateFieldDeclaration extends AtomicFieldDeclaration {
|
|
26
27
|
elementType: string;
|
|
28
|
+
outputsValue(): boolean;
|
|
27
29
|
typecheckExprValue(expr: ExprValue): void;
|
|
28
30
|
executesInOutputSpace(): boolean;
|
|
29
31
|
}
|
|
30
32
|
export declare class AggregateFieldDeclaration extends AtomicFieldDeclaration {
|
|
31
33
|
elementType: string;
|
|
34
|
+
outputsValue(): boolean;
|
|
32
35
|
typecheckExprValue(expr: ExprValue): void;
|
|
33
36
|
}
|
|
34
37
|
export declare class GroupByFieldDeclaration extends AtomicFieldDeclaration {
|
|
35
38
|
elementType: string;
|
|
39
|
+
outputsValue(): boolean;
|
|
36
40
|
typecheckExprValue(expr: ExprValue): void;
|
|
37
41
|
}
|
|
38
42
|
export declare class ProjectFieldDeclaration extends AtomicFieldDeclaration {
|
|
39
43
|
elementType: string;
|
|
44
|
+
outputsValue(): boolean;
|
|
40
45
|
typecheckExprValue(expr: ExprValue): void;
|
|
41
46
|
}
|
|
42
47
|
export declare class DeclareFieldDeclaration extends AtomicFieldDeclaration {
|
|
@@ -45,6 +45,7 @@ const malloy_element_1 = require("../types/malloy-element");
|
|
|
45
45
|
const typecheck_utils_1 = require("./typecheck_utils");
|
|
46
46
|
const space_field_1 = require("../types/space-field");
|
|
47
47
|
const def_space_1 = require("../field-space/def-space");
|
|
48
|
+
const boolean_value_1 = require("../expressions/boolean-value");
|
|
48
49
|
class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
|
|
49
50
|
constructor(expr, defineName, exprSrc) {
|
|
50
51
|
super({ expr: expr });
|
|
@@ -71,6 +72,10 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
|
|
|
71
72
|
executesInOutputSpace() {
|
|
72
73
|
return false;
|
|
73
74
|
}
|
|
75
|
+
// The declaration is a result column of a query
|
|
76
|
+
outputsValue() {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
74
79
|
queryFieldDef(exprFS, exprName) {
|
|
75
80
|
var _a;
|
|
76
81
|
let exprValue;
|
|
@@ -105,27 +110,16 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
|
|
|
105
110
|
}
|
|
106
111
|
if ((0, malloy_types_1.isAtomicFieldType)(exprValue.type) && exprValue.type !== 'error') {
|
|
107
112
|
this.typecheckExprValue(exprValue);
|
|
113
|
+
if (this.outputsValue() &&
|
|
114
|
+
(0, boolean_value_1.booleanValueError)(exprFS, exprValue, 'as a result column', this.expr, (0, boolean_value_1.resultColumnHint)((_a = this.exprSrc) !== null && _a !== void 0 ? _a : '…'))) {
|
|
115
|
+
return { name: exprName, type: 'error' };
|
|
116
|
+
}
|
|
108
117
|
const ret = (0, malloy_types_1.mkFieldDef)(TDU.atomicDef(exprValue), exprName);
|
|
109
118
|
if (malloy_types_1.TD.isTemporal(ret) && (0, granular_result_1.isGranularResult)(exprValue)) {
|
|
110
119
|
ret.timeframe = exprValue.timeframe;
|
|
111
120
|
}
|
|
112
121
|
ret.location = this.location;
|
|
113
|
-
|
|
114
|
-
((_a = exprFS.dialectObj()) === null || _a === void 0 ? void 0 : _a.booleanType) === 'none') {
|
|
115
|
-
// when generating a boolean field on a database without boolean support
|
|
116
|
-
// map it to integers
|
|
117
|
-
ret.e = {
|
|
118
|
-
node: 'case',
|
|
119
|
-
kids: {
|
|
120
|
-
caseWhen: [exprValue.value],
|
|
121
|
-
caseThen: [{ node: 'numberLiteral', literal: '1' }],
|
|
122
|
-
caseElse: { node: 'numberLiteral', literal: '0' },
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
ret.e = exprValue.value;
|
|
128
|
-
}
|
|
122
|
+
ret.e = exprValue.value;
|
|
129
123
|
ret.drillExpression = this.expr.drillExpression();
|
|
130
124
|
ret.refSummary = exprValue.refSummary;
|
|
131
125
|
ret.ungroupings = exprValue.ungroupings;
|
|
@@ -163,6 +157,9 @@ class CalculateFieldDeclaration extends AtomicFieldDeclaration {
|
|
|
163
157
|
super(...arguments);
|
|
164
158
|
this.elementType = 'calculateFieldDeclaration';
|
|
165
159
|
}
|
|
160
|
+
outputsValue() {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
166
163
|
typecheckExprValue(expr) {
|
|
167
164
|
(0, typecheck_utils_1.typecheckCalculate)(expr, this);
|
|
168
165
|
}
|
|
@@ -176,6 +173,9 @@ class AggregateFieldDeclaration extends AtomicFieldDeclaration {
|
|
|
176
173
|
super(...arguments);
|
|
177
174
|
this.elementType = 'aggregateFieldDeclaration';
|
|
178
175
|
}
|
|
176
|
+
outputsValue() {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
179
|
typecheckExprValue(expr) {
|
|
180
180
|
(0, typecheck_utils_1.typecheckAggregate)(expr, this);
|
|
181
181
|
}
|
|
@@ -186,6 +186,9 @@ class GroupByFieldDeclaration extends AtomicFieldDeclaration {
|
|
|
186
186
|
super(...arguments);
|
|
187
187
|
this.elementType = 'groupByFieldDeclaration';
|
|
188
188
|
}
|
|
189
|
+
outputsValue() {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
189
192
|
typecheckExprValue(expr) {
|
|
190
193
|
(0, typecheck_utils_1.typecheckGroupBy)(expr, this);
|
|
191
194
|
}
|
|
@@ -196,6 +199,9 @@ class ProjectFieldDeclaration extends AtomicFieldDeclaration {
|
|
|
196
199
|
super(...arguments);
|
|
197
200
|
this.elementType = 'projectFieldDeclaration';
|
|
198
201
|
}
|
|
202
|
+
outputsValue() {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
199
205
|
typecheckExprValue(expr) {
|
|
200
206
|
(0, typecheck_utils_1.typecheckProject)(expr, this);
|
|
201
207
|
}
|
|
@@ -25,6 +25,7 @@ export declare abstract class FieldReference extends ListOf<FieldName> implement
|
|
|
25
25
|
get sourceString(): string | undefined;
|
|
26
26
|
get nameString(): string;
|
|
27
27
|
abstract typecheck(type: TypeDesc): void;
|
|
28
|
+
outputsValue(): boolean;
|
|
28
29
|
getField(fs: FieldSpace): LookupResult;
|
|
29
30
|
}
|
|
30
31
|
export declare class AcceptExceptFieldReference extends FieldReference {
|
|
@@ -61,27 +62,32 @@ export declare class DrillFieldReference extends FieldReference {
|
|
|
61
62
|
}
|
|
62
63
|
export declare class CalculateFieldReference extends FieldReference {
|
|
63
64
|
elementType: string;
|
|
65
|
+
outputsValue(): boolean;
|
|
64
66
|
protected autoRenameDeclarationCtor(): typeof CalculateFieldDeclaration;
|
|
65
67
|
typecheck(type: TypeDesc): void;
|
|
66
68
|
}
|
|
67
69
|
export declare class IndexFieldReference extends FieldReference {
|
|
68
70
|
elementType: string;
|
|
71
|
+
outputsValue(): boolean;
|
|
69
72
|
typecheck(type: TypeDesc): void;
|
|
70
73
|
static indexOutputName(path: string[]): string;
|
|
71
74
|
get outputName(): string;
|
|
72
75
|
}
|
|
73
76
|
export declare class AggregateFieldReference extends FieldReference {
|
|
74
77
|
elementType: string;
|
|
78
|
+
outputsValue(): boolean;
|
|
75
79
|
protected autoRenameDeclarationCtor(): typeof AggregateFieldDeclaration;
|
|
76
80
|
typecheck(type: TypeDesc): void;
|
|
77
81
|
}
|
|
78
82
|
export declare class GroupByFieldReference extends FieldReference {
|
|
79
83
|
elementType: string;
|
|
84
|
+
outputsValue(): boolean;
|
|
80
85
|
protected autoRenameDeclarationCtor(): typeof GroupByFieldDeclaration;
|
|
81
86
|
typecheck(type: TypeDesc): void;
|
|
82
87
|
}
|
|
83
88
|
export declare class ProjectFieldReference extends FieldReference {
|
|
84
89
|
elementType: string;
|
|
90
|
+
outputsValue(): boolean;
|
|
85
91
|
protected autoRenameDeclarationCtor(): typeof ProjectFieldDeclaration;
|
|
86
92
|
typecheck(type: TypeDesc): void;
|
|
87
93
|
}
|
|
@@ -10,6 +10,7 @@ const definition_list_1 = require("../types/definition-list");
|
|
|
10
10
|
const field_space_1 = require("../types/field-space");
|
|
11
11
|
const malloy_element_1 = require("../types/malloy-element");
|
|
12
12
|
const expr_id_reference_1 = require("../expressions/expr-id-reference");
|
|
13
|
+
const boolean_value_1 = require("../expressions/boolean-value");
|
|
13
14
|
const field_declaration_1 = require("./field-declaration");
|
|
14
15
|
const typecheck_utils_1 = require("./typecheck_utils");
|
|
15
16
|
class FieldReference extends malloy_element_1.ListOf {
|
|
@@ -108,11 +109,18 @@ class FieldReference extends malloy_element_1.ListOf {
|
|
|
108
109
|
get nameString() {
|
|
109
110
|
return this.list[this.list.length - 1].refString;
|
|
110
111
|
}
|
|
112
|
+
// The reference is a result column of a query
|
|
113
|
+
outputsValue() {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
111
116
|
getField(fs) {
|
|
112
117
|
const result = fs.lookup(this.list);
|
|
113
118
|
if (result.found) {
|
|
114
119
|
const actualType = result.found.typeDesc();
|
|
115
120
|
this.typecheck(actualType);
|
|
121
|
+
if (this.outputsValue()) {
|
|
122
|
+
(0, boolean_value_1.booleanValueError)(fs, actualType, 'as a result column', this, (0, boolean_value_1.resultColumnHint)(this.refString));
|
|
123
|
+
}
|
|
116
124
|
}
|
|
117
125
|
return result;
|
|
118
126
|
}
|
|
@@ -210,6 +218,9 @@ class CalculateFieldReference extends FieldReference {
|
|
|
210
218
|
super(...arguments);
|
|
211
219
|
this.elementType = 'calculateFieldReference';
|
|
212
220
|
}
|
|
221
|
+
outputsValue() {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
213
224
|
autoRenameDeclarationCtor() {
|
|
214
225
|
return field_declaration_1.CalculateFieldDeclaration;
|
|
215
226
|
}
|
|
@@ -223,6 +234,9 @@ class IndexFieldReference extends FieldReference {
|
|
|
223
234
|
super(...arguments);
|
|
224
235
|
this.elementType = 'indexFieldReference';
|
|
225
236
|
}
|
|
237
|
+
outputsValue() {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
226
240
|
typecheck(type) {
|
|
227
241
|
(0, typecheck_utils_1.typecheckIndex)(type, this);
|
|
228
242
|
}
|
|
@@ -240,6 +254,9 @@ class AggregateFieldReference extends FieldReference {
|
|
|
240
254
|
super(...arguments);
|
|
241
255
|
this.elementType = 'aggregateFieldReference';
|
|
242
256
|
}
|
|
257
|
+
outputsValue() {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
243
260
|
autoRenameDeclarationCtor() {
|
|
244
261
|
return field_declaration_1.AggregateFieldDeclaration;
|
|
245
262
|
}
|
|
@@ -253,6 +270,9 @@ class GroupByFieldReference extends FieldReference {
|
|
|
253
270
|
super(...arguments);
|
|
254
271
|
this.elementType = 'groupByFieldReference';
|
|
255
272
|
}
|
|
273
|
+
outputsValue() {
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
256
276
|
autoRenameDeclarationCtor() {
|
|
257
277
|
return field_declaration_1.GroupByFieldDeclaration;
|
|
258
278
|
}
|
|
@@ -266,6 +286,9 @@ class ProjectFieldReference extends FieldReference {
|
|
|
266
286
|
super(...arguments);
|
|
267
287
|
this.elementType = 'projectFieldReference';
|
|
268
288
|
}
|
|
289
|
+
outputsValue() {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
269
292
|
autoRenameDeclarationCtor() {
|
|
270
293
|
return field_declaration_1.ProjectFieldDeclaration;
|
|
271
294
|
}
|
|
@@ -50,7 +50,9 @@ class FilterElement extends malloy_element_1.MalloyElement {
|
|
|
50
50
|
filterCondition(fs) {
|
|
51
51
|
const exprVal = this.expr.getExpression(fs);
|
|
52
52
|
if (exprVal.type !== 'boolean') {
|
|
53
|
-
|
|
53
|
+
if (exprVal.type !== 'error') {
|
|
54
|
+
this.expr.logError('non-boolean-filter', 'Filter expression must have boolean value');
|
|
55
|
+
}
|
|
54
56
|
return {
|
|
55
57
|
node: 'filterCondition',
|
|
56
58
|
code: this.exprSrc,
|
|
@@ -161,9 +161,22 @@ class ImportStatement extends malloy_element_1.ListOf {
|
|
|
161
161
|
// persistent ones. A `#@ -persist` wrapper that adds a join is
|
|
162
162
|
// not a table, but it can be the only way to reach the tables
|
|
163
163
|
// under it, and this model has to be able to take the same route.
|
|
164
|
+
//
|
|
165
|
+
// The persistent ones are also what a builder will build from
|
|
166
|
+
// this model, so the document checks at the end of compile that
|
|
167
|
+
// this model can supply every given their SQL reads.
|
|
164
168
|
if ((0, malloy_types_1.isSourceDef)(importMe) && (0, malloy_types_1.isPersistableSourceDef)(importMe)) {
|
|
165
169
|
for (const found of (0, persist_utils_1.walkPersistentDependencies)([importMe], importedModel)) {
|
|
166
170
|
neededSourceIDs.add(found.sourceID);
|
|
171
|
+
if (!found.persistent)
|
|
172
|
+
continue;
|
|
173
|
+
const def = (0, source_def_utils_1.resolveSourceID)(importedModel, found.sourceID);
|
|
174
|
+
if (def && !doc.importedPersistSources.has(found.sourceID)) {
|
|
175
|
+
doc.importedPersistSources.set(found.sourceID, {
|
|
176
|
+
source: def,
|
|
177
|
+
at: this.location,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
167
180
|
}
|
|
168
181
|
}
|
|
169
182
|
}
|
|
@@ -49,6 +49,7 @@ const granular_result_1 = require("./granular-result");
|
|
|
49
49
|
const malloy_element_1 = require("./malloy-element");
|
|
50
50
|
const binary_operators_1 = require("./binary_operators");
|
|
51
51
|
const malloy_filter_1 = require("@malloydata/malloy-filter");
|
|
52
|
+
const boolean_value_1 = require("../expressions/boolean-value");
|
|
52
53
|
class TypeMismatch extends Error {
|
|
53
54
|
}
|
|
54
55
|
/**
|
|
@@ -341,11 +342,21 @@ function regexEqual(left, right) {
|
|
|
341
342
|
}
|
|
342
343
|
return undefined;
|
|
343
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* A boolean can only be compared, with anything, on a dialect with boolean
|
|
347
|
+
* values. Every comparison operator, applied plainly, as a partial, or
|
|
348
|
+
* through an alternation, arrives here through equality() or compare().
|
|
349
|
+
*/
|
|
350
|
+
function booleanCompare(fs, left, lhs, op, right, rhs) {
|
|
351
|
+
const [side, val] = lhs.type === 'boolean' ? [left, lhs] : [right, rhs];
|
|
352
|
+
return (0, boolean_value_1.booleanValueError)(fs, val, `compared with ${op}`, side, boolean_value_1.COMPARE_HINT);
|
|
353
|
+
}
|
|
344
354
|
function equality(fs, left, op, right) {
|
|
345
355
|
const lhs = left.getExpression(fs);
|
|
346
356
|
const rhs = right.getExpression(fs);
|
|
347
357
|
const node = (0, binary_operators_1.getExprNode)(op);
|
|
348
|
-
const err = errorCascade('boolean', lhs, rhs)
|
|
358
|
+
const err = errorCascade('boolean', lhs, rhs) ||
|
|
359
|
+
booleanCompare(fs, left, lhs, op, right, rhs);
|
|
349
360
|
if (err)
|
|
350
361
|
return err;
|
|
351
362
|
// Unsupported types can be compare with null
|
|
@@ -365,6 +376,9 @@ function equality(fs, left, op, right) {
|
|
|
365
376
|
if (op !== '~' && op !== '!~') {
|
|
366
377
|
return right.loggedErrorExpr('filter-expression-error', `Cannot use the '${op}' operator with a filter expression`);
|
|
367
378
|
}
|
|
379
|
+
const noMatch = (0, boolean_value_1.booleanValueError)(fs, lhs, 'matched with a filter expression', left, 'test the condition itself');
|
|
380
|
+
if (noMatch)
|
|
381
|
+
return noMatch;
|
|
368
382
|
if ((0, malloy_filter_1.isFilterable)(lhs.type)) {
|
|
369
383
|
let actualFilter = rhs.value;
|
|
370
384
|
while (actualFilter.node === '()') {
|
|
@@ -419,7 +433,8 @@ function equality(fs, left, op, right) {
|
|
|
419
433
|
function compare(fs, left, op, right) {
|
|
420
434
|
const lhs = left.getExpression(fs);
|
|
421
435
|
const rhs = right.getExpression(fs);
|
|
422
|
-
const err = errorCascade('boolean', lhs, rhs)
|
|
436
|
+
const err = errorCascade('boolean', lhs, rhs) ||
|
|
437
|
+
booleanCompare(fs, left, lhs, op, right, rhs);
|
|
423
438
|
if (err)
|
|
424
439
|
return err;
|
|
425
440
|
const noCompare = unsupportError(left, lhs, right, rhs);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnnotationsDef, DocumentLocation, DocumentReference, Given, ModelDef, ModelAnnotationEntry, ModelID, NamedModelObject, Query, SourceID, SourceRegistryValue } from '../../../model/malloy_types';
|
|
1
|
+
import type { AnnotationsDef, DocumentLocation, DocumentReference, Given, ModelDef, ModelAnnotationEntry, ModelID, NamedModelObject, PersistableSourceDef, Query, SourceID, SourceRegistryValue } from '../../../model/malloy_types';
|
|
2
2
|
import { Tag } from '@malloydata/malloy-tag';
|
|
3
3
|
import type { LogMessageOptions, MessageLogger, MessageParameterType, MessageCode } from '../../parse-log';
|
|
4
4
|
import type { MalloyTranslation } from '../../parse-malloy';
|
|
@@ -116,6 +116,13 @@ export declare class Document extends MalloyElement implements NameSpace {
|
|
|
116
116
|
documentModel: Map<string, ModelEntry>;
|
|
117
117
|
documentSrcRegistry: Record<SourceID, SourceRegistryValue>;
|
|
118
118
|
documentGivens: Map<string, Given>;
|
|
119
|
+
/** Every persistent source an `import` brought within reach of this model's
|
|
120
|
+
* builder, with the import that did so. Checked at end of compile: the
|
|
121
|
+
* model has to be able to supply every given their SQL reads. */
|
|
122
|
+
importedPersistSources: Map<string, {
|
|
123
|
+
source: PersistableSourceDef;
|
|
124
|
+
at: DocumentLocation;
|
|
125
|
+
}>;
|
|
119
126
|
/** {@link ModelAnnotationEntry} of every imported/extended model in the
|
|
120
127
|
* closure, keyed by ModelID, accumulated as imports/extends are processed;
|
|
121
128
|
* copied into the result `modelAnnotations` in {@link modelDef}, which then
|
|
@@ -146,7 +153,23 @@ export declare class Document extends MalloyElement implements NameSpace {
|
|
|
146
153
|
initModelDef(extendingModelDef: ModelDef | undefined): void;
|
|
147
154
|
compile(): DocumentCompileResult;
|
|
148
155
|
private checkGivenAliasCollisions;
|
|
156
|
+
/**
|
|
157
|
+
* The givens in `usage` this model can neither supply nor default: not
|
|
158
|
+
* surfaced in the namespace and declared without a default. The set checked
|
|
159
|
+
* is each id plus its precomputed default-chain closure (`Given.givenUsage`),
|
|
160
|
+
* which is already transitive, so there is no recursion here.
|
|
161
|
+
*/
|
|
162
|
+
private unsatisfiedGivens;
|
|
149
163
|
private checkQueryGivenSatisfiability;
|
|
164
|
+
/**
|
|
165
|
+
* A persisted source is built from whatever model a builder is handed, so a
|
|
166
|
+
* model that imports one has to be able to supply every given its SQL reads;
|
|
167
|
+
* an import that cannot is a source no build or query here could ever use.
|
|
168
|
+
* Checked at end of compile rather than at the import, since the given may
|
|
169
|
+
* be imported by a later statement. A locally declared source cannot fail
|
|
170
|
+
* this: `$NAME` only resolves to a given in scope.
|
|
171
|
+
*/
|
|
172
|
+
private checkPersistSourceGivenSatisfiability;
|
|
150
173
|
hasAnnotation(): boolean;
|
|
151
174
|
currentModelAnnotation(): AnnotationsDef | undefined;
|
|
152
175
|
modelDef(): ModelDef;
|
|
@@ -9,6 +9,7 @@ exports.isDocStatement = isDocStatement;
|
|
|
9
9
|
exports.isDocStatementOrDocStatementList = isDocStatementOrDocStatementList;
|
|
10
10
|
const dialect_1 = require("../../../dialect");
|
|
11
11
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
12
|
+
const sql_compiled_1 = require("../../../model/sql_compiled");
|
|
12
13
|
const utils_1 = require("../../../model/utils");
|
|
13
14
|
const malloy_tag_1 = require("@malloydata/malloy-tag");
|
|
14
15
|
const parse_log_1 = require("../../parse-log");
|
|
@@ -436,6 +437,10 @@ class Document extends MalloyElement {
|
|
|
436
437
|
this.documentModel = new Map();
|
|
437
438
|
this.documentSrcRegistry = {};
|
|
438
439
|
this.documentGivens = new Map();
|
|
440
|
+
/** Every persistent source an `import` brought within reach of this model's
|
|
441
|
+
* builder, with the import that did so. Checked at end of compile: the
|
|
442
|
+
* model has to be able to supply every given their SQL reads. */
|
|
443
|
+
this.importedPersistSources = new Map();
|
|
439
444
|
/** {@link ModelAnnotationEntry} of every imported/extended model in the
|
|
440
445
|
* closure, keyed by ModelID, accumulated as imports/extends are processed;
|
|
441
446
|
* copied into the result `modelAnnotations` in {@link modelDef}, which then
|
|
@@ -512,6 +517,7 @@ class Document extends MalloyElement {
|
|
|
512
517
|
if (needs === undefined) {
|
|
513
518
|
this.checkGivenAliasCollisions();
|
|
514
519
|
this.checkQueryGivenSatisfiability();
|
|
520
|
+
this.checkPersistSourceGivenSatisfiability();
|
|
515
521
|
}
|
|
516
522
|
const ret = {
|
|
517
523
|
modelDef: {
|
|
@@ -553,40 +559,46 @@ class Document extends MalloyElement {
|
|
|
553
559
|
`with a default-chain reference: \`given: NEW_NAME :: T is $${sourceName}\`.`);
|
|
554
560
|
}
|
|
555
561
|
}
|
|
562
|
+
/**
|
|
563
|
+
* The givens in `usage` this model can neither supply nor default: not
|
|
564
|
+
* surfaced in the namespace and declared without a default. The set checked
|
|
565
|
+
* is each id plus its precomputed default-chain closure (`Given.givenUsage`),
|
|
566
|
+
* which is already transitive, so there is no recursion here.
|
|
567
|
+
*/
|
|
568
|
+
unsatisfiedGivens(usage) {
|
|
569
|
+
var _a, _b;
|
|
570
|
+
const namespaceGivens = new Set();
|
|
571
|
+
for (const m of this.documentModel.values()) {
|
|
572
|
+
if (m.entry.type === 'given')
|
|
573
|
+
namespaceGivens.add(m.entry.id);
|
|
574
|
+
}
|
|
575
|
+
const allIds = new Set();
|
|
576
|
+
for (const g of usage) {
|
|
577
|
+
allIds.add(g.id);
|
|
578
|
+
const decl = this.documentGivens.get(g.id);
|
|
579
|
+
for (const t of (_a = decl === null || decl === void 0 ? void 0 : decl.givenUsage) !== null && _a !== void 0 ? _a : [])
|
|
580
|
+
allIds.add(t.id);
|
|
581
|
+
}
|
|
582
|
+
const unsatisfied = [];
|
|
583
|
+
for (const id of allIds) {
|
|
584
|
+
if (namespaceGivens.has(id))
|
|
585
|
+
continue;
|
|
586
|
+
if (((_b = this.documentGivens.get(id)) === null || _b === void 0 ? void 0 : _b.default) !== undefined)
|
|
587
|
+
continue;
|
|
588
|
+
unsatisfied.push(id);
|
|
589
|
+
}
|
|
590
|
+
return unsatisfied;
|
|
591
|
+
}
|
|
556
592
|
checkQueryGivenSatisfiability() {
|
|
557
593
|
// Always runs at end-of-compile, not gated on imports — a notebook cell
|
|
558
594
|
// that calls `extendModel` with a prior modelDef inherits that model's
|
|
559
595
|
// queries and givens, and a query inherited from cell N can become
|
|
560
596
|
// unsatisfiable in cell N+1 if the satisfying given is removed (or
|
|
561
597
|
// never re-supplied). Cheap when there's nothing to check.
|
|
562
|
-
const namespaceGivens = new Set();
|
|
563
|
-
for (const m of this.documentModel.values()) {
|
|
564
|
-
if (m.entry.type === 'given')
|
|
565
|
-
namespaceGivens.add(m.entry.id);
|
|
566
|
-
}
|
|
567
598
|
const checkOne = (q, label) => {
|
|
568
599
|
var _a;
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
return;
|
|
572
|
-
// Build the full set of ids the query transitively needs: each id
|
|
573
|
-
// in Q.givenUsage, plus each id's precomputed default-chain closure
|
|
574
|
-
// (Given.givenUsage). Since the closure is already transitive, no
|
|
575
|
-
// recursion at check time.
|
|
576
|
-
const allIds = new Set();
|
|
577
|
-
for (const g of usage) {
|
|
578
|
-
allIds.add(g.id);
|
|
579
|
-
const decl = this.documentGivens.get(g.id);
|
|
580
|
-
for (const t of (_a = decl === null || decl === void 0 ? void 0 : decl.givenUsage) !== null && _a !== void 0 ? _a : [])
|
|
581
|
-
allIds.add(t.id);
|
|
582
|
-
}
|
|
583
|
-
for (const id of allIds) {
|
|
584
|
-
if (namespaceGivens.has(id))
|
|
585
|
-
continue;
|
|
586
|
-
const decl = this.documentGivens.get(id);
|
|
587
|
-
if ((decl === null || decl === void 0 ? void 0 : decl.default) !== undefined)
|
|
588
|
-
continue;
|
|
589
|
-
this.logError('unsatisfied-given-in-query', unsatisfiedGivenMessage(label, decl, id), { at: q.location });
|
|
600
|
+
for (const id of this.unsatisfiedGivens((_a = q.givenUsage) !== null && _a !== void 0 ? _a : [])) {
|
|
601
|
+
this.logError('unsatisfied-given-in-query', unsatisfiedGivenMessage(label, this.documentGivens.get(id), id), { at: q.location });
|
|
590
602
|
}
|
|
591
603
|
};
|
|
592
604
|
// Named queries in the namespace (locally defined OR imported).
|
|
@@ -599,6 +611,31 @@ class Document extends MalloyElement {
|
|
|
599
611
|
checkOne(q, 'run: statement');
|
|
600
612
|
}
|
|
601
613
|
}
|
|
614
|
+
/**
|
|
615
|
+
* A persisted source is built from whatever model a builder is handed, so a
|
|
616
|
+
* model that imports one has to be able to supply every given its SQL reads;
|
|
617
|
+
* an import that cannot is a source no build or query here could ever use.
|
|
618
|
+
* Checked at end of compile rather than at the import, since the given may
|
|
619
|
+
* be imported by a later statement. A locally declared source cannot fail
|
|
620
|
+
* this: `$NAME` only resolves to a given in scope.
|
|
621
|
+
*/
|
|
622
|
+
checkPersistSourceGivenSatisfiability() {
|
|
623
|
+
var _a;
|
|
624
|
+
// One import routinely reaches several sources that share a table — a
|
|
625
|
+
// persisted source and its extensions — so each given is reported once
|
|
626
|
+
// per import, against the first source that reads it.
|
|
627
|
+
const reported = new Map();
|
|
628
|
+
for (const { source, at } of this.importedPersistSources.values()) {
|
|
629
|
+
const seen = (_a = reported.get(at)) !== null && _a !== void 0 ? _a : new Set();
|
|
630
|
+
reported.set(at, seen);
|
|
631
|
+
for (const id of this.unsatisfiedGivens((0, sql_compiled_1.givenUsageOfRelation)(source))) {
|
|
632
|
+
if (seen.has(id))
|
|
633
|
+
continue;
|
|
634
|
+
seen.add(id);
|
|
635
|
+
this.logError('unsatisfied-given-in-persist-source', unsatisfiedGivenMessage(`Imported persisted source \`${(0, malloy_types_1.activeName)(source)}\``, this.documentGivens.get(id), id), { at });
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
602
639
|
hasAnnotation() {
|
|
603
640
|
return ((this.annotations.notes && this.annotations.notes.length > 0) ||
|
|
604
641
|
this.annotations.inherits !== undefined);
|
|
@@ -8,6 +8,7 @@ exports.ReferenceView = void 0;
|
|
|
8
8
|
const composite_source_utils_1 = require("../../composite-source-utils");
|
|
9
9
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
10
10
|
const error_factory_1 = require("../error-factory");
|
|
11
|
+
const boolean_value_1 = require("../expressions/boolean-value");
|
|
11
12
|
const drill_1 = require("../query-properties/drill");
|
|
12
13
|
const space_field_1 = require("../types/space-field");
|
|
13
14
|
const refine_utils_1 = require("./refine-utils");
|
|
@@ -55,6 +56,9 @@ class ReferenceView extends view_1.View {
|
|
|
55
56
|
throw new Error('Expected field to have definition');
|
|
56
57
|
}
|
|
57
58
|
if ((0, malloy_types_1.isAtomic)(fieldDef)) {
|
|
59
|
+
if ((0, boolean_value_1.booleanValueError)(fs, fieldDef, 'as a result column', this.reference, (0, boolean_value_1.resultColumnHint)(this.reference.refString))) {
|
|
60
|
+
return oops();
|
|
61
|
+
}
|
|
58
62
|
const name = this.reference.nameString;
|
|
59
63
|
const outputStruct = {
|
|
60
64
|
...(0, malloy_types_1.sourceBase)(fs.structDef()),
|