@malloydata/malloy 0.0.433 → 0.0.435
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 +2 -2
- package/dist/api/foundation/compile.js +8 -9
- package/dist/api/foundation/config.js +6 -15
- package/dist/api/foundation/runtime.d.ts +2 -8
- package/dist/api/foundation/runtime.js +11 -39
- package/dist/api/foundation/types.d.ts +1 -1
- package/dist/connection/validate_table_path.d.ts +1 -2
- package/dist/connection/validate_table_path.js +1 -2
- package/dist/dialect/databricks/databricks.js +6 -6
- package/dist/dialect/dialect.d.ts +35 -3
- package/dist/dialect/dialect.js +67 -5
- package/dist/dialect/dialect_map.js +2 -0
- package/dist/dialect/duckdb/duckdb.js +7 -21
- package/dist/dialect/index.d.ts +2 -1
- package/dist/dialect/index.js +3 -1
- package/dist/dialect/mysql/mysql.js +8 -8
- package/dist/dialect/pg_impl.js +12 -12
- package/dist/dialect/postgres/postgres.js +3 -3
- package/dist/dialect/snowflake/snowflake.js +12 -12
- package/dist/dialect/sqlserver/dialect_functions.d.ts +2 -0
- package/dist/dialect/sqlserver/dialect_functions.js +42 -0
- package/dist/dialect/sqlserver/function_overrides.d.ts +2 -0
- package/dist/dialect/sqlserver/function_overrides.js +55 -0
- package/dist/dialect/sqlserver/index.d.ts +1 -0
- package/dist/dialect/sqlserver/index.js +22 -0
- package/dist/dialect/sqlserver/sqlserver.d.ts +102 -0
- package/dist/dialect/sqlserver/sqlserver.js +538 -0
- package/dist/dialect/sqlserver/windows_zones.d.ts +1 -0
- package/dist/dialect/sqlserver/windows_zones.js +613 -0
- package/dist/dialect/standardsql/standardsql.d.ts +1 -1
- package/dist/dialect/standardsql/standardsql.js +16 -13
- package/dist/dialect/trino/trino.d.ts +3 -3
- package/dist/dialect/trino/trino.js +32 -28
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -3
- package/dist/lang/ast/source-elements/named-source.js +0 -2
- package/dist/lang/ast/source-elements/refined-source.js +1 -1
- package/dist/lang/ast/source-elements/sql-source.js +2 -4
- package/dist/lang/ast/source-elements/table-source.js +1 -2
- package/dist/lang/ast/source-properties/timezone-statement.d.ts +4 -3
- package/dist/lang/ast/source-properties/timezone-statement.js +14 -12
- package/dist/lang/ast/statements/import-statement.js +4 -0
- package/dist/lang/ast/types/malloy-element.d.ts +0 -7
- package/dist/lang/ast/types/malloy-element.js +0 -18
- package/dist/lang/composite-source-utils.js +10 -3
- package/dist/lang/malloy-to-ast.js +2 -8
- package/dist/lang/parse-malloy.d.ts +20 -4
- package/dist/lang/parse-malloy.js +50 -15
- package/dist/lang/parse-tree-walkers/find-external-references.d.ts +3 -3
- package/dist/lang/parse-tree-walkers/find-external-references.js +17 -16
- package/dist/lang/test/test-translator.d.ts +12 -2
- package/dist/lang/test/test-translator.js +16 -2
- package/dist/model/expression_compiler.js +1 -1
- package/dist/model/join_instance.d.ts +1 -0
- package/dist/model/join_instance.js +9 -1
- package/dist/model/query_query.d.ts +28 -1
- package/dist/model/query_query.js +299 -156
- package/dist/model/source_def_utils.d.ts +7 -1
- package/dist/model/source_def_utils.js +20 -0
- package/dist/model/sql_block.d.ts +2 -2
- package/dist/model/sql_block.js +11 -47
- package/dist/model/sql_compiled.d.ts +3 -1
- package/dist/model/sql_compiled.js +8 -6
- package/dist/model/stage_writer.js +3 -3
- package/dist/model/utils.d.ts +2 -2
- package/dist/model/utils.js +2 -3
- package/dist/test/index.js +16 -8
- package/dist/test/matchers.d.ts +1 -1
- package/dist/test/matchers.js +1 -1
- package/dist/test/test-models.js +6 -13
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/femto-config.motly +15 -1
- package/package.json +7 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { DocumentLocation, DocumentPosition, DocumentReference, ImportLocation, ModelDef, SourceDef, SQLSourceDef, DependencyTree, DocumentRange } from '../model/malloy_types';
|
|
1
|
+
import type { DocumentLocation, DocumentPosition, DocumentReference, ImportLocation, ModelDef, SourceDef, SQLSourceDef, DependencyTree, DocumentRange, VirtualMap } from '../model/malloy_types';
|
|
2
2
|
import type { LogMessage, LogMessageOptions, MessageCode, MessageParameterType } from './parse-log';
|
|
3
3
|
import { BaseMessageLogger } from './parse-log';
|
|
4
|
+
import type { FindReferencesData } from './parse-tree-walkers/find-external-references';
|
|
4
5
|
import type { ZoneData } from './zone';
|
|
5
6
|
import { Zone } from './zone';
|
|
6
7
|
import { ReferenceList } from './reference-list';
|
|
@@ -52,7 +53,7 @@ declare class ParseStep implements TranslationStep {
|
|
|
52
53
|
}
|
|
53
54
|
declare class ImportsAndTablesStep implements TranslationStep {
|
|
54
55
|
readonly parseStep: ParseStep;
|
|
55
|
-
|
|
56
|
+
parseReferences: FindReferencesData | undefined;
|
|
56
57
|
constructor(parseStep: ParseStep);
|
|
57
58
|
step(that: MalloyTranslation): DataRequestResponse | ParseResponse;
|
|
58
59
|
}
|
|
@@ -61,6 +62,16 @@ declare class ASTStep implements TranslationStep {
|
|
|
61
62
|
response?: ASTResponse;
|
|
62
63
|
private walked;
|
|
63
64
|
constructor(importStep: ImportsAndTablesStep);
|
|
65
|
+
/**
|
|
66
|
+
* A file acknowledges an experimental dialect with
|
|
67
|
+
* `##! experimental.dialect.NAME` wherever it names a connection on that
|
|
68
|
+
* dialect. Every connection name in this file is already resolved to a
|
|
69
|
+
* dialect by the time the AST exists, and the file's compiler flags are
|
|
70
|
+
* known only now, so this is the first moment the check can run. The
|
|
71
|
+
* other place a file takes on a dialect is `import`, checked by
|
|
72
|
+
* `ImportStatement`.
|
|
73
|
+
*/
|
|
74
|
+
private checkExperimentalDialects;
|
|
64
75
|
step(that: MalloyTranslation): ASTResponse;
|
|
65
76
|
}
|
|
66
77
|
declare class MetadataStep implements TranslationStep {
|
|
@@ -166,8 +177,12 @@ export declare abstract class MalloyTranslation {
|
|
|
166
177
|
rangeFromContext(pcx: ParserRuleContext): DocumentRange;
|
|
167
178
|
private dialectAlreadyChecked;
|
|
168
179
|
firstReferenceToDialect(dialect: string): boolean;
|
|
169
|
-
allDialectsEnabled: boolean;
|
|
170
180
|
experimentalDialectEnabled(dialect: string): boolean;
|
|
181
|
+
/**
|
|
182
|
+
* Log, once per dialect per file, that this file uses an experimental
|
|
183
|
+
* dialect without acknowledging it.
|
|
184
|
+
*/
|
|
185
|
+
checkExperimentalDialect(dialect: string, at: DocumentLocation): void;
|
|
171
186
|
}
|
|
172
187
|
export declare class MalloyChildTranslator extends MalloyTranslation {
|
|
173
188
|
readonly root: MalloyTranslator;
|
|
@@ -186,6 +201,7 @@ export declare class MalloyChildTranslator extends MalloyTranslation {
|
|
|
186
201
|
export declare class MalloyTranslator extends MalloyTranslation {
|
|
187
202
|
private readonly eventStream;
|
|
188
203
|
readonly restrictedMode: boolean;
|
|
204
|
+
virtualMap?: VirtualMap | undefined;
|
|
189
205
|
schemaZone: Zone<SourceDef>;
|
|
190
206
|
importZone: Zone<string>;
|
|
191
207
|
pretranslatedModels: Map<string, ModelDef>;
|
|
@@ -193,7 +209,7 @@ export declare class MalloyTranslator extends MalloyTranslation {
|
|
|
193
209
|
connectionDialectZone: Zone<string>;
|
|
194
210
|
logger: BaseMessageLogger;
|
|
195
211
|
readonly root: MalloyTranslator;
|
|
196
|
-
constructor(rootURL: string, importURL?: string | null, preload?: ParseUpdate | null, eventStream?: EventStream | null, restrictedMode?: boolean);
|
|
212
|
+
constructor(rootURL: string, importURL?: string | null, preload?: ParseUpdate | null, eventStream?: EventStream | null, restrictedMode?: boolean, virtualMap?: VirtualMap | undefined);
|
|
197
213
|
update(dd: ParseUpdate): void;
|
|
198
214
|
private lockZonesIfRestricted;
|
|
199
215
|
translate(extendingModel?: ModelDef): TranslateResponse;
|
|
@@ -38,6 +38,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
})();
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.MalloyTranslator = exports.MalloyChildTranslator = exports.MalloyTranslation = void 0;
|
|
41
|
+
const malloy_types_1 = require("../model/malloy_types");
|
|
41
42
|
const utils_1 = require("../model/utils");
|
|
42
43
|
const annotation_utils_1 = require("../model/annotation_utils");
|
|
43
44
|
const ast = __importStar(require("./ast"));
|
|
@@ -132,14 +133,13 @@ class ImportsAndTablesStep {
|
|
|
132
133
|
// Register connection dialects and imports immediately. Table
|
|
133
134
|
// references are deferred until dialects are resolved, because
|
|
134
135
|
// validating a table path requires knowing its dialect's grammar.
|
|
135
|
-
for (const connName
|
|
136
|
+
for (const [connName, need] of this.parseReferences.connectionDialects) {
|
|
136
137
|
that.root.connectionDialectZone.reference(connName, {
|
|
137
138
|
url: that.sourceURL,
|
|
138
|
-
range:
|
|
139
|
+
range: need.firstReference,
|
|
139
140
|
});
|
|
140
141
|
}
|
|
141
|
-
for (const relativeRef
|
|
142
|
-
const firstRef = this.parseReferences.urls[relativeRef];
|
|
142
|
+
for (const [relativeRef, firstRef] of this.parseReferences.urls) {
|
|
143
143
|
try {
|
|
144
144
|
const ref = decodeURI(new URL(relativeRef, that.importBaseURL || that.sourceURL).toString());
|
|
145
145
|
that.addChild(ref);
|
|
@@ -171,8 +171,7 @@ class ImportsAndTablesStep {
|
|
|
171
171
|
// Invalid paths are dropped here and re-reported by the AST step.
|
|
172
172
|
// tableRequests feeds the missing-table loop below.
|
|
173
173
|
const tableRequests = {};
|
|
174
|
-
for (const
|
|
175
|
-
const info = this.parseReferences.tables[rawKey];
|
|
174
|
+
for (const info of this.parseReferences.tables.values()) {
|
|
176
175
|
const dialectName = that.root.connectionDialectZone.get(info.connectionName);
|
|
177
176
|
if (dialectName === undefined)
|
|
178
177
|
continue;
|
|
@@ -204,7 +203,9 @@ class ImportsAndTablesStep {
|
|
|
204
203
|
}
|
|
205
204
|
const missingDialects = that.root.connectionDialectZone.getUndefined();
|
|
206
205
|
if (missingDialects) {
|
|
207
|
-
|
|
206
|
+
// Keyed by connection name, user text: a plain `{}` would turn a
|
|
207
|
+
// connection named `__proto__` into a prototype and drop the request.
|
|
208
|
+
const connectionDialects = (0, malloy_types_1.mkSafeRecord)();
|
|
208
209
|
for (const connName of missingDialects) {
|
|
209
210
|
connectionDialects[connName] = { connectionName: connName };
|
|
210
211
|
}
|
|
@@ -237,6 +238,31 @@ class ASTStep {
|
|
|
237
238
|
this.importStep = importStep;
|
|
238
239
|
this.walked = false;
|
|
239
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* A file acknowledges an experimental dialect with
|
|
243
|
+
* `##! experimental.dialect.NAME` wherever it names a connection on that
|
|
244
|
+
* dialect. Every connection name in this file is already resolved to a
|
|
245
|
+
* dialect by the time the AST exists, and the file's compiler flags are
|
|
246
|
+
* known only now, so this is the first moment the check can run. The
|
|
247
|
+
* other place a file takes on a dialect is `import`, checked by
|
|
248
|
+
* `ImportStatement`.
|
|
249
|
+
*/
|
|
250
|
+
checkExperimentalDialects(that) {
|
|
251
|
+
var _a;
|
|
252
|
+
const connections = (_a = this.importStep.parseReferences) === null || _a === void 0 ? void 0 : _a.connectionDialects;
|
|
253
|
+
if (!connections) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
for (const [connName, need] of connections) {
|
|
257
|
+
const dialect = that.root.connectionDialectZone.get(connName);
|
|
258
|
+
if (dialect !== undefined) {
|
|
259
|
+
that.checkExperimentalDialect(dialect, {
|
|
260
|
+
url: that.sourceURL,
|
|
261
|
+
range: need.firstReference,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
240
266
|
step(that) {
|
|
241
267
|
const stepTimer = new timing_1.Timer('ast_step');
|
|
242
268
|
if (this.response) {
|
|
@@ -262,6 +288,7 @@ class ASTStep {
|
|
|
262
288
|
const { ast: newAST, compilerFlagSrc, timingInfo } = secondPass.run();
|
|
263
289
|
stepTimer.contribute([timingInfo]);
|
|
264
290
|
that.compilerFlagSrc = compilerFlagSrc;
|
|
291
|
+
this.checkExperimentalDialects(that);
|
|
265
292
|
if (newAST.elementType === 'unimplemented') {
|
|
266
293
|
newAST.logError('untranslated-parse-node', 'INTERNAL COMPILER ERROR: Untranslated parse node');
|
|
267
294
|
}
|
|
@@ -429,9 +456,9 @@ class TranslateStep {
|
|
|
429
456
|
// seeding (e.g. TestTranslator's compilerFlags option) survive.
|
|
430
457
|
if (extendingModel && !this.importedAnnotations) {
|
|
431
458
|
const parseCompilerFlagsTimer = new timing_1.Timer('parse_compiler_flags');
|
|
432
|
-
//
|
|
433
|
-
//
|
|
434
|
-
//
|
|
459
|
+
// `##!` is a pragma: it governs the file it sits in and does not cross
|
|
460
|
+
// `import`. An extension is a continuation of the base's text, so the
|
|
461
|
+
// base's flags are in force here.
|
|
435
462
|
that.compilerFlagSrc.push(...new annotation_1.Annotations((0, annotation_utils_1.getModelAnnotations)(extendingModel)).texts('!'));
|
|
436
463
|
stepTimer.contribute([parseCompilerFlagsTimer.stop()]);
|
|
437
464
|
this.importedAnnotations = true;
|
|
@@ -515,7 +542,6 @@ class MalloyTranslation {
|
|
|
515
542
|
Not sure where the logic for this needs to go, this is just my first guess
|
|
516
543
|
*/
|
|
517
544
|
this.dialectAlreadyChecked = {};
|
|
518
|
-
this.allDialectsEnabled = false;
|
|
519
545
|
this.childTranslators = new Map();
|
|
520
546
|
this.modelDef = (0, utils_1.mkModelDef)(sourceURL, (0, utils_1.mkModelID)(sourceURL));
|
|
521
547
|
/**
|
|
@@ -753,13 +779,21 @@ class MalloyTranslation {
|
|
|
753
779
|
return true;
|
|
754
780
|
}
|
|
755
781
|
experimentalDialectEnabled(dialect) {
|
|
756
|
-
if (this.allDialectsEnabled) {
|
|
757
|
-
return true;
|
|
758
|
-
}
|
|
759
782
|
const experimental = this.getCompilerFlags().tag('experimental');
|
|
760
783
|
return (experimental !== undefined &&
|
|
761
784
|
(experimental.bare() || experimental.has('dialect', dialect)));
|
|
762
785
|
}
|
|
786
|
+
/**
|
|
787
|
+
* Log, once per dialect per file, that this file uses an experimental
|
|
788
|
+
* dialect without acknowledging it.
|
|
789
|
+
*/
|
|
790
|
+
checkExperimentalDialect(dialect, at) {
|
|
791
|
+
if (this.firstReferenceToDialect(dialect) &&
|
|
792
|
+
(0, dialect_1.getDialect)(dialect).isExperimental() &&
|
|
793
|
+
!this.experimentalDialectEnabled(dialect)) {
|
|
794
|
+
this.root.logError('experimental-dialect-not-enabled', { dialect }, { at });
|
|
795
|
+
}
|
|
796
|
+
}
|
|
763
797
|
}
|
|
764
798
|
exports.MalloyTranslation = MalloyTranslation;
|
|
765
799
|
class MalloyChildTranslator extends MalloyTranslation {
|
|
@@ -780,10 +814,11 @@ exports.MalloyChildTranslator = MalloyChildTranslator;
|
|
|
780
814
|
* no need to call again, the translation is finished or error'd.
|
|
781
815
|
*/
|
|
782
816
|
class MalloyTranslator extends MalloyTranslation {
|
|
783
|
-
constructor(rootURL, importURL = null, preload = null, eventStream = null, restrictedMode = false) {
|
|
817
|
+
constructor(rootURL, importURL = null, preload = null, eventStream = null, restrictedMode = false, virtualMap) {
|
|
784
818
|
super(rootURL, importURL);
|
|
785
819
|
this.eventStream = eventStream;
|
|
786
820
|
this.restrictedMode = restrictedMode;
|
|
821
|
+
this.virtualMap = virtualMap;
|
|
787
822
|
this.schemaZone = new zone_1.Zone();
|
|
788
823
|
this.importZone = new zone_1.Zone();
|
|
789
824
|
this.pretranslatedModels = new Map();
|
|
@@ -2,13 +2,13 @@ import type { CommonTokenStream } from 'antlr4ts';
|
|
|
2
2
|
import type { ParseTree } from 'antlr4ts/tree';
|
|
3
3
|
import type { DocumentRange } from '../../model/malloy_types';
|
|
4
4
|
import type { MalloyTranslation } from '../parse-malloy';
|
|
5
|
-
type NeedImports =
|
|
6
|
-
type NeedTables =
|
|
5
|
+
type NeedImports = Map<string, DocumentRange>;
|
|
6
|
+
type NeedTables = Map<string, {
|
|
7
7
|
connectionName: string;
|
|
8
8
|
tablePath: string;
|
|
9
9
|
firstReference: DocumentRange;
|
|
10
10
|
}>;
|
|
11
|
-
type NeedConnectionDialects =
|
|
11
|
+
type NeedConnectionDialects = Map<string, {
|
|
12
12
|
firstReference: DocumentRange;
|
|
13
13
|
}>;
|
|
14
14
|
export declare function constructTableKey(connectionName: string, tablePath: string): string;
|
|
@@ -32,18 +32,18 @@ class FindExternalReferences {
|
|
|
32
32
|
constructor(trans, tokens) {
|
|
33
33
|
this.trans = trans;
|
|
34
34
|
this.tokens = tokens;
|
|
35
|
-
this.needTables =
|
|
36
|
-
this.needImports =
|
|
37
|
-
this.needConnectionDialects =
|
|
35
|
+
this.needTables = new Map();
|
|
36
|
+
this.needImports = new Map();
|
|
37
|
+
this.needConnectionDialects = new Map();
|
|
38
38
|
}
|
|
39
39
|
registerTableReference(connectionName, tablePath, reference) {
|
|
40
40
|
const key = constructTableKey(connectionName, tablePath);
|
|
41
|
-
if (!this.needTables
|
|
42
|
-
this.needTables
|
|
41
|
+
if (!this.needTables.has(key)) {
|
|
42
|
+
this.needTables.set(key, {
|
|
43
43
|
connectionName,
|
|
44
44
|
tablePath,
|
|
45
45
|
firstReference: reference,
|
|
46
|
-
};
|
|
46
|
+
});
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
enterExploreTable(pcx) {
|
|
@@ -53,22 +53,23 @@ class FindExternalReferences {
|
|
|
53
53
|
this.registerTableReference(connId, tablePath, reference);
|
|
54
54
|
// Register a need for the connection's dialect so the validator in
|
|
55
55
|
// ImportsAndTablesStep can run against it.
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
this.registerConnection(connId, reference);
|
|
57
|
+
}
|
|
58
|
+
registerConnection(connId, reference) {
|
|
59
|
+
if (connId && !this.needConnectionDialects.has(connId)) {
|
|
60
|
+
this.needConnectionDialects.set(connId, { firstReference: reference });
|
|
58
61
|
}
|
|
59
62
|
}
|
|
63
|
+
enterSqlSource(pcx) {
|
|
64
|
+
this.registerConnection((0, parse_utils_1.getId)(pcx.connectionId()), this.trans.rangeFromContext(pcx));
|
|
65
|
+
}
|
|
60
66
|
enterVirtualSource(pcx) {
|
|
61
|
-
|
|
62
|
-
if (connId && !this.needConnectionDialects[connId]) {
|
|
63
|
-
this.needConnectionDialects[connId] = {
|
|
64
|
-
firstReference: this.trans.rangeFromContext(pcx),
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
+
this.registerConnection((0, parse_utils_1.getId)(pcx.connectionId()), this.trans.rangeFromContext(pcx));
|
|
67
68
|
}
|
|
68
69
|
enterImportURL(pcx) {
|
|
69
70
|
const url = getPlainString(pcx);
|
|
70
|
-
if (!this.needImports
|
|
71
|
-
this.needImports
|
|
71
|
+
if (!this.needImports.has(url)) {
|
|
72
|
+
this.needImports.set(url, this.trans.rangeFromContext(pcx));
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { DocumentLocation, FieldDef, ModelDef, NamedModelObject, PipeSegment, Query, QueryFieldDef, StructDef, TurtleDef, SourceDef, TableSourceDef, SQLSourceDef, UserTypeDef } from '../../model/malloy_types';
|
|
1
|
+
import type { DocumentLocation, FieldDef, ModelDef, NamedModelObject, PipeSegment, Query, QueryFieldDef, StructDef, TurtleDef, SourceDef, TableSourceDef, SQLSourceDef, UserTypeDef, VirtualMap } from '../../model/malloy_types';
|
|
2
2
|
import { MalloyElement } from '../ast';
|
|
3
3
|
import type { NameSpace } from '../ast/types/name-space';
|
|
4
4
|
import type { ModelEntry } from '../ast/types/model-entry';
|
|
5
5
|
import { MalloyChildTranslator, MalloyTranslator } from '../parse-malloy';
|
|
6
|
+
import { Zone } from '../zone';
|
|
6
7
|
import type { DataRequestResponse, SQLSourceRequest, TranslateResponse } from '../translate-response';
|
|
7
8
|
import type { ExprValue } from '../ast/types/expr-value';
|
|
8
9
|
import type { LogSeverity, MessageCode, MessageParameterType } from '../parse-log';
|
|
@@ -56,6 +57,7 @@ export interface TestTranslatorOptions {
|
|
|
56
57
|
eventStream?: EventStream | null;
|
|
57
58
|
internalModel?: ModelDef;
|
|
58
59
|
restrictedMode?: boolean;
|
|
60
|
+
virtualMap?: VirtualMap;
|
|
59
61
|
/**
|
|
60
62
|
* Each entry is a compiler-flag tag fragment — the content that
|
|
61
63
|
* would follow `##! ` in a Malloy source annotation. Rendered to
|
|
@@ -65,10 +67,18 @@ export interface TestTranslatorOptions {
|
|
|
65
67
|
*/
|
|
66
68
|
compilerFlags?: string[];
|
|
67
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Every connection name a test mentions resolves to a dialect, as it would
|
|
72
|
+
* through a host's connection lookup: the four listed below to theirs, and
|
|
73
|
+
* any other name to `TEST_DIALECT`.
|
|
74
|
+
*/
|
|
75
|
+
declare class TestConnectionDialectZone extends Zone<string> {
|
|
76
|
+
reference(str: string, loc: DocumentLocation): void;
|
|
77
|
+
}
|
|
68
78
|
export declare class TestTranslator extends MalloyTranslator {
|
|
69
79
|
readonly testSrc: string;
|
|
70
|
-
allDialectsEnabled: boolean;
|
|
71
80
|
testRoot?: TestRoot;
|
|
81
|
+
connectionDialectZone: TestConnectionDialectZone;
|
|
72
82
|
internalModel: ModelDef;
|
|
73
83
|
constructor(testSrc: string, options?: TestTranslatorOptions);
|
|
74
84
|
translate(): TranslateResponse;
|
|
@@ -29,6 +29,7 @@ const util_1 = require("util");
|
|
|
29
29
|
const malloy_types_1 = require("../../model/malloy_types");
|
|
30
30
|
const ast_1 = require("../ast");
|
|
31
31
|
const parse_malloy_1 = require("../parse-malloy");
|
|
32
|
+
const zone_1 = require("../zone");
|
|
32
33
|
const static_space_1 = require("../ast/field-space/static-space");
|
|
33
34
|
const global_name_space_1 = require("../ast/types/global-name-space");
|
|
34
35
|
const sql_block_1 = require("../../model/sql_block");
|
|
@@ -336,12 +337,25 @@ class TestChildTranslator extends parse_malloy_1.MalloyChildTranslator {
|
|
|
336
337
|
}
|
|
337
338
|
exports.TestChildTranslator = TestChildTranslator;
|
|
338
339
|
const testURI = 'internal://test/langtests/root.malloy';
|
|
340
|
+
/**
|
|
341
|
+
* Every connection name a test mentions resolves to a dialect, as it would
|
|
342
|
+
* through a host's connection lookup: the four listed below to theirs, and
|
|
343
|
+
* any other name to `TEST_DIALECT`.
|
|
344
|
+
*/
|
|
345
|
+
class TestConnectionDialectZone extends zone_1.Zone {
|
|
346
|
+
reference(str, loc) {
|
|
347
|
+
super.reference(str, loc);
|
|
348
|
+
if (this.getEntry(str).status === 'reference') {
|
|
349
|
+
this.define(str, exports.TEST_DIALECT);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
339
353
|
class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
340
354
|
constructor(testSrc, options = {}) {
|
|
341
355
|
var _a, _b, _c, _d, _e;
|
|
342
|
-
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);
|
|
356
|
+
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, options.virtualMap);
|
|
343
357
|
this.testSrc = testSrc;
|
|
344
|
-
this.
|
|
358
|
+
this.connectionDialectZone = new TestConnectionDialectZone();
|
|
345
359
|
/*
|
|
346
360
|
* There are four connections:
|
|
347
361
|
* _db_ - duckdb dialect, with the following tables ...
|
|
@@ -225,7 +225,7 @@ function compileExpr(resultSet, context, expr, state = new utils_1.GenerateState
|
|
|
225
225
|
return `${expr.e.sql} IS NOT NULL`;
|
|
226
226
|
case 'true':
|
|
227
227
|
case 'false':
|
|
228
|
-
return expr.node;
|
|
228
|
+
return context.dialect.sqlBoolean(expr.node === 'true');
|
|
229
229
|
case 'null':
|
|
230
230
|
return 'NULL';
|
|
231
231
|
case 'case':
|
|
@@ -12,6 +12,7 @@ export declare class JoinInstance {
|
|
|
12
12
|
joinFilterConditions?: QueryFieldBoolean[];
|
|
13
13
|
children: JoinInstance[];
|
|
14
14
|
constructor(queryStruct: QueryStruct, alias: string, parent: JoinInstance | undefined);
|
|
15
|
+
isSubquery(): boolean;
|
|
15
16
|
parentRelationship(): 'root' | JoinRelationship;
|
|
16
17
|
forceAllSymmetricCalculations(): boolean;
|
|
17
18
|
getDialectFieldList(): DialectFieldList;
|
|
@@ -30,6 +30,14 @@ class JoinInstance {
|
|
|
30
30
|
}, this.queryStruct));
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
// A filtered join whose own joins go inside its subquery, so that the
|
|
34
|
+
// subquery has to project them back out for anything outside to name them.
|
|
35
|
+
isSubquery() {
|
|
36
|
+
return (this.children.length > 0 &&
|
|
37
|
+
this.joinFilterConditions !== undefined &&
|
|
38
|
+
(0, malloy_types_1.isJoinedSource)(this.queryStruct.structDef) &&
|
|
39
|
+
this.queryStruct.dialect.supportsComplexFilteredSources);
|
|
40
|
+
}
|
|
33
41
|
parentRelationship() {
|
|
34
42
|
if (this.queryStruct.parent === undefined) {
|
|
35
43
|
return 'root';
|
|
@@ -64,7 +72,7 @@ class JoinInstance {
|
|
|
64
72
|
}
|
|
65
73
|
// postgres unnest needs to know the names of the physical fields.
|
|
66
74
|
getDialectFieldList() {
|
|
67
|
-
return (0, utils_1.getDialectFieldList)(this.queryStruct.structDef);
|
|
75
|
+
return (0, utils_1.getDialectFieldList)(this.queryStruct.structDef, this.queryStruct.dialect);
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
exports.JoinInstance = JoinInstance;
|
|
@@ -17,8 +17,10 @@ type StageGroupMaping = {
|
|
|
17
17
|
};
|
|
18
18
|
interface StageOutputColumn {
|
|
19
19
|
sql: string;
|
|
20
|
+
expr: string;
|
|
20
21
|
name: string;
|
|
21
22
|
isDimension: boolean;
|
|
23
|
+
constant?: boolean;
|
|
22
24
|
}
|
|
23
25
|
type StageOutputContext = {
|
|
24
26
|
columns: StageOutputColumn[];
|
|
@@ -34,6 +36,7 @@ export declare class QueryQuery extends QueryField {
|
|
|
34
36
|
maxDepth: number;
|
|
35
37
|
maxGroupSet: number;
|
|
36
38
|
rootResult: FieldInstanceResultRoot;
|
|
39
|
+
private packedColumns;
|
|
37
40
|
resultStage: string | undefined;
|
|
38
41
|
stageWriter: StageWriter | undefined;
|
|
39
42
|
isJoinedSubquery: boolean;
|
|
@@ -90,6 +93,30 @@ export declare class QueryQuery extends QueryField {
|
|
|
90
93
|
sql?: string;
|
|
91
94
|
};
|
|
92
95
|
generateSQLJoinBlock(stageWriter: StageWriter, ji: JoinInstance, depth: number): string;
|
|
96
|
+
/**
|
|
97
|
+
* Which column of which join a reference needs, or undefined when it needs
|
|
98
|
+
* none. Walking `path` from `from`, the answer is the member of the
|
|
99
|
+
* innermost join along it -- a record is kept whole, since a reference into
|
|
100
|
+
* one is a reference to the column holding it.
|
|
101
|
+
*
|
|
102
|
+
* Two kinds of path need no column. One ending at a computed field
|
|
103
|
+
* contributes that field's name, which is no column of the source; the
|
|
104
|
+
* columns the computation reads arrive as references of their own. And a
|
|
105
|
+
* `having:` or `calculate:` names an *output* field, so its path is rooted
|
|
106
|
+
* in the query's output rather than its source and need not resolve here at
|
|
107
|
+
* all. An output name which happens to match a source column resolves as
|
|
108
|
+
* though it were one, which costs nothing: a query's own source is never
|
|
109
|
+
* packed, only the joins beneath a filtered one.
|
|
110
|
+
*/
|
|
111
|
+
private packedColumnFor;
|
|
112
|
+
/**
|
|
113
|
+
* Which columns of each join have to survive being packed into a struct:
|
|
114
|
+
* every column the segment's field usage names, plus each join's primary
|
|
115
|
+
* key, which the compiler reaches for as a distinct key without any
|
|
116
|
+
* expression in the query naming it.
|
|
117
|
+
*/
|
|
118
|
+
private packedColumnsByJoin;
|
|
119
|
+
private joinProjectionFieldList;
|
|
93
120
|
generateSQLPassthroughKeys(qs: QueryStruct): string;
|
|
94
121
|
generateSQLJoins(stageWriter: StageWriter): string;
|
|
95
122
|
/**
|
|
@@ -97,7 +124,7 @@ export declare class QueryQuery extends QueryField {
|
|
|
97
124
|
* This ordering ensures parent arrays are ordered before child arrays.
|
|
98
125
|
*/
|
|
99
126
|
collectArrayJoins(ji: JoinInstance): JoinInstance[];
|
|
100
|
-
genereateSQLOrderBy(queryDef: QuerySegment, resultStruct: FieldInstanceResult): string;
|
|
127
|
+
genereateSQLOrderBy(queryDef: QuerySegment, resultStruct: FieldInstanceResult): string[];
|
|
101
128
|
/**
|
|
102
129
|
* The single-scan form, with no `group_set` fan-out: one `SELECT` over the
|
|
103
130
|
* scan, grouped by the dimensions. Used both for a query with no nests and --
|