@malloydata/malloy 0.0.219 → 0.0.220-dev241204170603
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/connection/base_connection.js +1 -1
- package/dist/dialect/dialect.d.ts +6 -3
- package/dist/dialect/dialect.js +4 -11
- package/dist/dialect/duckdb/dialect_functions.js +1 -1
- package/dist/dialect/duckdb/duckdb.d.ts +4 -4
- package/dist/dialect/duckdb/duckdb.js +10 -16
- package/dist/dialect/duckdb/function_overrides.js +1 -1
- package/dist/dialect/functions/malloy_standard_functions.js +1 -1
- package/dist/dialect/index.d.ts +3 -1
- package/dist/dialect/index.js +3 -1
- package/dist/dialect/mysql/dialect_functions.js +1 -1
- package/dist/dialect/mysql/function_overrides.js +1 -1
- package/dist/dialect/mysql/index.js +1 -1
- package/dist/dialect/mysql/mysql.d.ts +9 -6
- package/dist/dialect/mysql/mysql.js +36 -25
- package/dist/dialect/pg_impl.d.ts +4 -1
- package/dist/dialect/pg_impl.js +11 -1
- package/dist/dialect/postgres/dialect_functions.js +1 -1
- package/dist/dialect/postgres/function_overrides.js +1 -1
- package/dist/dialect/postgres/postgres.d.ts +6 -4
- package/dist/dialect/postgres/postgres.js +27 -12
- package/dist/dialect/snowflake/dialect_functions.js +1 -1
- package/dist/dialect/snowflake/function_overrides.js +1 -1
- package/dist/dialect/snowflake/snowflake.d.ts +5 -3
- package/dist/dialect/snowflake/snowflake.js +76 -20
- package/dist/dialect/standardsql/dialect_functions.js +1 -1
- package/dist/dialect/standardsql/function_overrides.js +1 -1
- package/dist/dialect/standardsql/standardsql.d.ts +5 -3
- package/dist/dialect/standardsql/standardsql.js +16 -101
- package/dist/dialect/tiny_parser.d.ts +41 -0
- package/dist/dialect/tiny_parser.js +126 -0
- package/dist/dialect/trino/dialect_functions.js +1 -1
- package/dist/dialect/trino/function_overrides.js +1 -1
- package/dist/dialect/trino/trino.d.ts +3 -3
- package/dist/dialect/trino/trino.js +40 -16
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -2
- package/dist/lang/ast/expressions/case.js +1 -1
- package/dist/lang/ast/expressions/expr-array-literal.d.ts +9 -0
- package/dist/lang/ast/expressions/expr-array-literal.js +93 -0
- package/dist/lang/ast/expressions/expr-record-literal.d.ts +1 -1
- package/dist/lang/ast/expressions/expr-record-literal.js +56 -28
- package/dist/lang/ast/field-space/join-space-field.d.ts +1 -1
- package/dist/lang/ast/field-space/join-space-field.js +2 -2
- package/dist/lang/ast/field-space/project-field-space.js +1 -1
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/field-space/static-space.d.ts +1 -2
- package/dist/lang/ast/field-space/static-space.js +15 -5
- package/dist/lang/ast/field-space/view-field.d.ts +2 -2
- package/dist/lang/ast/index.d.ts +1 -0
- package/dist/lang/ast/index.js +1 -0
- package/dist/lang/ast/query-items/field-declaration.js +25 -11
- package/dist/lang/ast/query-properties/filters.js +0 -2
- package/dist/lang/ast/source-properties/join.js +1 -1
- package/dist/lang/ast/types/binary_operators.js +1 -1
- package/dist/lang/ast/types/dialect-name-space.js +1 -1
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +1 -1
- package/dist/lang/lib/Malloy/MalloyParser.js +12 -16
- package/dist/lang/malloy-to-ast.d.ts +1 -1
- package/dist/lang/malloy-to-ast.js +3 -3
- package/dist/lang/parse-log.d.ts +1 -0
- package/dist/lang/test/query.spec.js +6 -0
- package/dist/lang/test/test-translator.js +11 -2
- package/dist/model/malloy_query.d.ts +29 -24
- package/dist/model/malloy_query.js +261 -146
- package/dist/model/malloy_types.d.ts +12 -15
- package/dist/model/malloy_types.js +2 -7
- package/dist/model/materialization/utils.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -173,13 +173,6 @@ class StageWriter {
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
|
-
// type QueryNodeType =
|
|
177
|
-
// | "abstract"
|
|
178
|
-
// | "dimension"
|
|
179
|
-
// | "measure"
|
|
180
|
-
// | "query"
|
|
181
|
-
// | "turtle"
|
|
182
|
-
// | "struct";
|
|
183
176
|
class GenerateState {
|
|
184
177
|
constructor() {
|
|
185
178
|
this.totalGroupSet = -1;
|
|
@@ -234,6 +227,9 @@ class QueryField extends QueryNode {
|
|
|
234
227
|
}
|
|
235
228
|
return parent;
|
|
236
229
|
}
|
|
230
|
+
isAtomic() {
|
|
231
|
+
return (0, malloy_types_1.isAtomic)(this.fieldDef);
|
|
232
|
+
}
|
|
237
233
|
caseGroup(groupSets, s) {
|
|
238
234
|
if (groupSets.length === 0) {
|
|
239
235
|
return s;
|
|
@@ -900,33 +896,47 @@ class QueryField extends QueryNode {
|
|
|
900
896
|
return (parentDef.type === 'array' &&
|
|
901
897
|
parentDef.elementTypeDef.type !== 'record_element');
|
|
902
898
|
}
|
|
903
|
-
|
|
899
|
+
generateExpression(resultSet) {
|
|
900
|
+
// If the field itself is an expression, generate it ..
|
|
904
901
|
if ((0, malloy_types_1.hasExpression)(this.fieldDef)) {
|
|
905
|
-
return this.fieldDef.e;
|
|
902
|
+
return this.exprToSQL(resultSet, this.parent, this.fieldDef.e);
|
|
906
903
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
904
|
+
// The field itself is not an expression, so we would like
|
|
905
|
+
// to generate a dotted path to the field, EXCEPT ...
|
|
906
|
+
// some of the steps in the dotting might not exist
|
|
907
|
+
// in the namespace of their parent, but rather be record
|
|
908
|
+
// expressions which should be evaluated in the namespace
|
|
909
|
+
// of their parent.
|
|
910
|
+
// So we walk the tree and ask each one to compute itself
|
|
911
|
+
for (let ancestor = this.parent; ancestor !== undefined; ancestor = ancestor.parent) {
|
|
912
|
+
if (ancestor.structDef.type === 'record' &&
|
|
913
|
+
(0, malloy_types_1.hasExpression)(ancestor.structDef) &&
|
|
914
|
+
ancestor.recordAlias === undefined) {
|
|
915
|
+
if (!ancestor.parent) {
|
|
916
|
+
throw new Error('Inconcievable record ancestor with expression but no parent');
|
|
917
|
+
}
|
|
918
|
+
const aliasValue = this.exprToSQL(resultSet, ancestor.parent, ancestor.structDef.e);
|
|
919
|
+
ancestor.informOfAliasValue(aliasValue);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return this.parent.sqlChildReference(this.fieldDef.name, this.parent.structDef.type === 'record'
|
|
923
|
+
? {
|
|
924
|
+
result: resultSet,
|
|
925
|
+
field: this,
|
|
926
|
+
}
|
|
927
|
+
: undefined);
|
|
918
928
|
}
|
|
919
929
|
}
|
|
920
930
|
function isCalculatedField(f) {
|
|
921
|
-
return f instanceof
|
|
931
|
+
return f instanceof AbstractQueryAtomic && f.isCalculated();
|
|
922
932
|
}
|
|
923
933
|
function isAggregateField(f) {
|
|
924
|
-
return f instanceof
|
|
934
|
+
return f instanceof AbstractQueryAtomic && f.isAggregate();
|
|
925
935
|
}
|
|
926
936
|
function isScalarField(f) {
|
|
927
|
-
return f instanceof
|
|
937
|
+
return (f instanceof AbstractQueryAtomic && !f.isCalculated() && !f.isAggregate());
|
|
928
938
|
}
|
|
929
|
-
class
|
|
939
|
+
class AbstractQueryAtomic extends QueryField {
|
|
930
940
|
constructor(fieldDef, parent, refId) {
|
|
931
941
|
super(fieldDef, parent, refId);
|
|
932
942
|
this.fieldDef = fieldDef; // wish I didn't have to do this
|
|
@@ -948,28 +958,32 @@ class QueryAtomicField extends QueryField {
|
|
|
948
958
|
hasExpression() {
|
|
949
959
|
return (0, malloy_types_1.hasExpression)(this.fieldDef);
|
|
950
960
|
}
|
|
961
|
+
isAtomic() {
|
|
962
|
+
return true;
|
|
963
|
+
}
|
|
951
964
|
}
|
|
952
965
|
// class QueryMeasure extends QueryField {}
|
|
953
|
-
class QueryFieldString extends
|
|
966
|
+
class QueryFieldString extends AbstractQueryAtomic {
|
|
954
967
|
}
|
|
955
|
-
class QueryFieldNumber extends
|
|
968
|
+
class QueryFieldNumber extends AbstractQueryAtomic {
|
|
956
969
|
}
|
|
957
|
-
class QueryFieldBoolean extends
|
|
970
|
+
class QueryFieldBoolean extends AbstractQueryAtomic {
|
|
958
971
|
}
|
|
959
|
-
class QueryFieldJSON extends
|
|
972
|
+
class QueryFieldJSON extends AbstractQueryAtomic {
|
|
960
973
|
}
|
|
961
|
-
class QueryFieldUnsupported extends
|
|
974
|
+
class QueryFieldUnsupported extends AbstractQueryAtomic {
|
|
962
975
|
}
|
|
963
|
-
class QueryFieldDate extends
|
|
976
|
+
class QueryFieldDate extends AbstractQueryAtomic {
|
|
964
977
|
generateExpression(resultSet) {
|
|
965
978
|
const fd = this.fieldDef;
|
|
979
|
+
const superExpr = super.generateExpression(resultSet);
|
|
966
980
|
if (!fd.timeframe) {
|
|
967
|
-
return
|
|
981
|
+
return superExpr;
|
|
968
982
|
}
|
|
969
983
|
else {
|
|
970
984
|
const truncated = {
|
|
971
985
|
node: 'trunc',
|
|
972
|
-
e: (0, malloy_types_1.mkTemporal)(
|
|
986
|
+
e: (0, malloy_types_1.mkTemporal)({ node: 'genericSQLExpr', src: [superExpr], kids: { args: [] } }, 'date'),
|
|
973
987
|
units: fd.timeframe,
|
|
974
988
|
};
|
|
975
989
|
return this.exprToSQL(resultSet, this.parent, truncated);
|
|
@@ -985,7 +999,7 @@ class QueryFieldDate extends QueryAtomicField {
|
|
|
985
999
|
return new QueryFieldDate(fieldDef, this.parent);
|
|
986
1000
|
}
|
|
987
1001
|
}
|
|
988
|
-
class QueryFieldTimestamp extends
|
|
1002
|
+
class QueryFieldTimestamp extends AbstractQueryAtomic {
|
|
989
1003
|
// clone ourselves on demand as a timeframe.
|
|
990
1004
|
getChildByName(name) {
|
|
991
1005
|
const fieldDef = {
|
|
@@ -996,7 +1010,7 @@ class QueryFieldTimestamp extends QueryAtomicField {
|
|
|
996
1010
|
return new QueryFieldTimestamp(fieldDef, this.parent);
|
|
997
1011
|
}
|
|
998
1012
|
}
|
|
999
|
-
class QueryFieldDistinctKey extends
|
|
1013
|
+
class QueryFieldDistinctKey extends AbstractQueryAtomic {
|
|
1000
1014
|
generateExpression(resultSet) {
|
|
1001
1015
|
var _a;
|
|
1002
1016
|
if (this.parent.primaryKey()) {
|
|
@@ -1006,11 +1020,11 @@ class QueryFieldDistinctKey extends QueryAtomicField {
|
|
|
1006
1020
|
else if (this.parent.structDef.type === 'array') {
|
|
1007
1021
|
const parentKey = (_a = this.parent.parent) === null || _a === void 0 ? void 0 : _a.getDistinctKey().generateExpression(resultSet);
|
|
1008
1022
|
return this.parent.dialect.sqlMakeUnnestKey(parentKey || '', // shouldn't have to do this...
|
|
1009
|
-
this.parent.dialect.sqlFieldReference(this.parent.getIdentifier(), '__row_id', 'string'
|
|
1023
|
+
this.parent.dialect.sqlFieldReference(this.parent.getIdentifier(), 'table', '__row_id', 'string'));
|
|
1010
1024
|
}
|
|
1011
1025
|
else {
|
|
1012
1026
|
// return this.parent.getIdentifier() + "." + "__distinct_key";
|
|
1013
|
-
return this.parent.dialect.sqlFieldReference(this.parent.getIdentifier(), '__distinct_key', 'string'
|
|
1027
|
+
return this.parent.dialect.sqlFieldReference(this.parent.getIdentifier(), 'table', '__distinct_key', 'string');
|
|
1014
1028
|
}
|
|
1015
1029
|
}
|
|
1016
1030
|
includeInWildcard() {
|
|
@@ -1219,7 +1233,7 @@ class FieldInstanceResult {
|
|
|
1219
1233
|
if (isScalarField(f.f)) {
|
|
1220
1234
|
return 'nested';
|
|
1221
1235
|
}
|
|
1222
|
-
if (f.f instanceof
|
|
1236
|
+
if (f.f instanceof QueryFieldStruct) {
|
|
1223
1237
|
ret = 'inline';
|
|
1224
1238
|
}
|
|
1225
1239
|
}
|
|
@@ -1313,7 +1327,9 @@ class FieldInstanceResult {
|
|
|
1313
1327
|
}
|
|
1314
1328
|
findJoins(query) {
|
|
1315
1329
|
for (const dim of this.fields()) {
|
|
1316
|
-
|
|
1330
|
+
if (!(dim.f instanceof QueryFieldStruct)) {
|
|
1331
|
+
this.addStructToJoin(dim.f.getJoinableParent(), query, dim.f.uniqueKeyPossibleUse(), []);
|
|
1332
|
+
}
|
|
1317
1333
|
}
|
|
1318
1334
|
for (const s of this.structs()) {
|
|
1319
1335
|
s.findJoins(query);
|
|
@@ -1526,9 +1542,6 @@ class JoinInstance {
|
|
|
1526
1542
|
return getDialectFieldList(this.queryStruct.structDef);
|
|
1527
1543
|
}
|
|
1528
1544
|
}
|
|
1529
|
-
/** nested query */
|
|
1530
|
-
class QueryTurtle extends QueryField {
|
|
1531
|
-
}
|
|
1532
1545
|
/**
|
|
1533
1546
|
* Used by the translator to get the output StructDef of a pipe segment
|
|
1534
1547
|
*
|
|
@@ -1622,20 +1635,30 @@ class QueryQuery extends QueryField {
|
|
|
1622
1635
|
return { as, field };
|
|
1623
1636
|
}
|
|
1624
1637
|
addDependantPath(resultStruct, context, path, uniqueKeyPossibleUse, joinStack) {
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
if (node instanceof QueryField) {
|
|
1628
|
-
struct = node.parent;
|
|
1629
|
-
}
|
|
1630
|
-
else if (node instanceof QueryStruct) {
|
|
1631
|
-
struct = node;
|
|
1632
|
-
}
|
|
1633
|
-
else {
|
|
1634
|
-
throw new Error('Internal Error: Unknown object type');
|
|
1638
|
+
if (path.length === 0) {
|
|
1639
|
+
return;
|
|
1635
1640
|
}
|
|
1641
|
+
const node = context.getFieldByName(path);
|
|
1642
|
+
const joinableParent = node instanceof QueryFieldStruct
|
|
1643
|
+
? node.queryStruct.getJoinableParent()
|
|
1644
|
+
: node.parent.getJoinableParent();
|
|
1636
1645
|
resultStruct
|
|
1637
1646
|
.root()
|
|
1638
|
-
.addStructToJoin(
|
|
1647
|
+
.addStructToJoin(joinableParent, this, uniqueKeyPossibleUse, joinStack);
|
|
1648
|
+
}
|
|
1649
|
+
findRecordAliases(context, path) {
|
|
1650
|
+
for (const seg of path) {
|
|
1651
|
+
const field = context.getFieldByName([seg]);
|
|
1652
|
+
if (field instanceof QueryFieldStruct) {
|
|
1653
|
+
const qs = field.queryStruct;
|
|
1654
|
+
if (qs.structDef.type === 'record' &&
|
|
1655
|
+
(0, malloy_types_1.hasExpression)(qs.structDef) &&
|
|
1656
|
+
qs.parent) {
|
|
1657
|
+
qs.informOfAliasValue(this.exprToSQL(this.rootResult, qs.parent, qs.structDef.e));
|
|
1658
|
+
}
|
|
1659
|
+
context = qs;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1639
1662
|
}
|
|
1640
1663
|
addDependantExpr(resultStruct, context, e, joinStack) {
|
|
1641
1664
|
var _a;
|
|
@@ -1679,6 +1702,7 @@ class QueryQuery extends QueryField {
|
|
|
1679
1702
|
}
|
|
1680
1703
|
}
|
|
1681
1704
|
if (expr.node === 'field') {
|
|
1705
|
+
this.findRecordAliases(context, expr.path);
|
|
1682
1706
|
const field = context.getDimensionOrMeasureByName(expr.path);
|
|
1683
1707
|
if ((0, malloy_types_1.hasExpression)(field.fieldDef)) {
|
|
1684
1708
|
this.addDependantExpr(resultStruct, field.parent, field.fieldDef.e, joinStack);
|
|
@@ -1692,6 +1716,7 @@ class QueryQuery extends QueryField {
|
|
|
1692
1716
|
else if (expr.node === 'aggregate') {
|
|
1693
1717
|
if ((0, malloy_types_1.isAsymmetricExpr)(expr)) {
|
|
1694
1718
|
if (expr.structPath) {
|
|
1719
|
+
this.findRecordAliases(context, expr.structPath);
|
|
1695
1720
|
this.addDependantPath(resultStruct, context, expr.structPath, expr.function, joinStack);
|
|
1696
1721
|
}
|
|
1697
1722
|
else {
|
|
@@ -1719,7 +1744,7 @@ class QueryQuery extends QueryField {
|
|
|
1719
1744
|
let resultIndex = 1;
|
|
1720
1745
|
for (const f of this.getSegmentFields(resultStruct)) {
|
|
1721
1746
|
const { as, field } = this.expandField(f);
|
|
1722
|
-
if (field instanceof
|
|
1747
|
+
if (field instanceof QueryQuery) {
|
|
1723
1748
|
if (this.firstSegment.type === 'project') {
|
|
1724
1749
|
throw new Error(`Nested views cannot be used in select - '${field.fieldDef.name}'`);
|
|
1725
1750
|
}
|
|
@@ -1727,7 +1752,7 @@ class QueryQuery extends QueryField {
|
|
|
1727
1752
|
this.expandFields(fir);
|
|
1728
1753
|
resultStruct.add(as, fir);
|
|
1729
1754
|
}
|
|
1730
|
-
else if (field instanceof
|
|
1755
|
+
else if (field instanceof AbstractQueryAtomic) {
|
|
1731
1756
|
resultStruct.addField(as, field, {
|
|
1732
1757
|
resultIndex,
|
|
1733
1758
|
type: 'result',
|
|
@@ -1738,16 +1763,12 @@ class QueryQuery extends QueryField {
|
|
|
1738
1763
|
throw new Error(`Aggregate Fields cannot be used in select - '${field.fieldDef.name}'`);
|
|
1739
1764
|
}
|
|
1740
1765
|
}
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
// resultIndex,
|
|
1748
|
-
// type: "result",
|
|
1749
|
-
// });
|
|
1750
|
-
// resultStruct.addStructToJoin(field, false);
|
|
1766
|
+
}
|
|
1767
|
+
else if (field instanceof QueryFieldStruct) {
|
|
1768
|
+
resultStruct.addField(as, field, {
|
|
1769
|
+
resultIndex,
|
|
1770
|
+
type: 'result',
|
|
1771
|
+
});
|
|
1751
1772
|
}
|
|
1752
1773
|
// else if (
|
|
1753
1774
|
// this.firstSegment.type === "project" &&
|
|
@@ -1818,8 +1839,8 @@ class QueryQuery extends QueryField {
|
|
|
1818
1839
|
const alwaysJoins = (_a = stage.alwaysJoins) !== null && _a !== void 0 ? _a : [];
|
|
1819
1840
|
for (const joinName of alwaysJoins) {
|
|
1820
1841
|
const qs = this.parent.getChildByName(joinName);
|
|
1821
|
-
if (qs instanceof
|
|
1822
|
-
rootResult.addStructToJoin(qs, this, undefined, []);
|
|
1842
|
+
if (qs instanceof QueryFieldStruct) {
|
|
1843
|
+
rootResult.addStructToJoin(qs.queryStruct, this, undefined, []);
|
|
1823
1844
|
}
|
|
1824
1845
|
}
|
|
1825
1846
|
}
|
|
@@ -1922,10 +1943,6 @@ class QueryQuery extends QueryField {
|
|
|
1922
1943
|
}
|
|
1923
1944
|
else if (fi instanceof FieldInstanceField) {
|
|
1924
1945
|
if (fi.fieldUsage.type === 'result') {
|
|
1925
|
-
// mtoy todo -- remember why you commented this out
|
|
1926
|
-
// if (fi.f instanceof QueryFieldStruct) {
|
|
1927
|
-
// fields.push(fi.f.getAsJoinedStructDef(name));
|
|
1928
|
-
// }
|
|
1929
1946
|
// if there is only one dimension, it is the primaryKey
|
|
1930
1947
|
// if there are more, primaryKey is undefined.
|
|
1931
1948
|
if (isScalarField(fi.f)) {
|
|
@@ -1937,16 +1954,25 @@ class QueryQuery extends QueryField {
|
|
|
1937
1954
|
}
|
|
1938
1955
|
dimCount++;
|
|
1939
1956
|
}
|
|
1940
|
-
|
|
1941
|
-
|
|
1957
|
+
// Remove computations because they are all resolved
|
|
1958
|
+
let fOut = fi.f.fieldDef;
|
|
1959
|
+
if ((0, malloy_types_1.hasExpression)(fOut)) {
|
|
1960
|
+
fOut = { ...fOut };
|
|
1961
|
+
// "as" because delete needs the property to be optional
|
|
1962
|
+
delete fOut.e;
|
|
1963
|
+
delete fOut.code;
|
|
1964
|
+
delete fOut.expressionType;
|
|
1965
|
+
}
|
|
1966
|
+
const location = fOut.location;
|
|
1967
|
+
const annotation = fOut.annotation;
|
|
1942
1968
|
// build out the result fields...
|
|
1943
|
-
switch (
|
|
1969
|
+
switch (fOut.type) {
|
|
1944
1970
|
case 'boolean':
|
|
1945
1971
|
case 'json':
|
|
1946
1972
|
case 'string':
|
|
1947
1973
|
fields.push({
|
|
1948
1974
|
name,
|
|
1949
|
-
type:
|
|
1975
|
+
type: fOut.type,
|
|
1950
1976
|
resultMetadata,
|
|
1951
1977
|
location,
|
|
1952
1978
|
annotation,
|
|
@@ -1954,8 +1980,8 @@ class QueryQuery extends QueryField {
|
|
|
1954
1980
|
break;
|
|
1955
1981
|
case 'date':
|
|
1956
1982
|
case 'timestamp': {
|
|
1957
|
-
const timeframe =
|
|
1958
|
-
const fd = { type:
|
|
1983
|
+
const timeframe = fOut.timeframe;
|
|
1984
|
+
const fd = { type: fOut.type };
|
|
1959
1985
|
if (timeframe) {
|
|
1960
1986
|
fd.timeframe = timeframe;
|
|
1961
1987
|
}
|
|
@@ -1971,7 +1997,7 @@ class QueryQuery extends QueryField {
|
|
|
1971
1997
|
case 'number':
|
|
1972
1998
|
fields.push({
|
|
1973
1999
|
name,
|
|
1974
|
-
numberType:
|
|
2000
|
+
numberType: fOut.numberType,
|
|
1975
2001
|
type: 'number',
|
|
1976
2002
|
resultMetadata,
|
|
1977
2003
|
location,
|
|
@@ -1979,10 +2005,13 @@ class QueryQuery extends QueryField {
|
|
|
1979
2005
|
});
|
|
1980
2006
|
break;
|
|
1981
2007
|
case 'sql native':
|
|
1982
|
-
|
|
2008
|
+
case 'record':
|
|
2009
|
+
case 'array': {
|
|
2010
|
+
fields.push({ ...fOut, resultMetadata });
|
|
1983
2011
|
break;
|
|
2012
|
+
}
|
|
1984
2013
|
default:
|
|
1985
|
-
throw new Error(`unknown Field Type in query ${JSON.stringify(
|
|
2014
|
+
throw new Error(`unknown Field Type in query ${JSON.stringify(fOut)}`);
|
|
1986
2015
|
}
|
|
1987
2016
|
}
|
|
1988
2017
|
}
|
|
@@ -2002,7 +2031,7 @@ class QueryQuery extends QueryField {
|
|
|
2002
2031
|
}
|
|
2003
2032
|
return outputStruct;
|
|
2004
2033
|
}
|
|
2005
|
-
generateSQLJoinBlock(stageWriter, ji) {
|
|
2034
|
+
generateSQLJoinBlock(stageWriter, ji, depth) {
|
|
2006
2035
|
var _a;
|
|
2007
2036
|
let s = '';
|
|
2008
2037
|
const qs = ji.queryStruct;
|
|
@@ -2063,7 +2092,7 @@ class QueryQuery extends QueryField {
|
|
|
2063
2092
|
let select = `SELECT ${ji.alias}.*`;
|
|
2064
2093
|
let joins = '';
|
|
2065
2094
|
for (const childJoin of ji.children) {
|
|
2066
|
-
joins += this.generateSQLJoinBlock(stageWriter, childJoin);
|
|
2095
|
+
joins += this.generateSQLJoinBlock(stageWriter, childJoin, depth + 1);
|
|
2067
2096
|
select += `, ${this.parent.dialect.sqlSelectAliasAsStruct(childJoin.alias, getDialectFieldList(childJoin.queryStruct.structDef))} AS ${childJoin.alias}`;
|
|
2068
2097
|
}
|
|
2069
2098
|
select += `\nFROM ${structSQL} AS ${ji.alias}\n${joins}\nWHERE ${conditions === null || conditions === void 0 ? void 0 : conditions.join(' AND ')}\n`;
|
|
@@ -2075,10 +2104,27 @@ class QueryQuery extends QueryField {
|
|
|
2075
2104
|
if (qs.parent === undefined || ji.parent === undefined) {
|
|
2076
2105
|
throw new Error('Internal Error, nested structure with no parent.');
|
|
2077
2106
|
}
|
|
2078
|
-
|
|
2107
|
+
// We need an SQL expression which results in the array for us to pass to un-nest
|
|
2108
|
+
let arrayExpression;
|
|
2109
|
+
if ((0, malloy_types_1.hasExpression)(qsDef)) {
|
|
2110
|
+
// If this array is NOT contained in the parent, but a computed entity
|
|
2111
|
+
// then the thing we are joining is not "parent.childName", but
|
|
2112
|
+
// the expression which is built in that namespace
|
|
2113
|
+
arrayExpression = this.exprToSQL(this.rootResult, qs.parent, qsDef.e);
|
|
2114
|
+
}
|
|
2115
|
+
else {
|
|
2116
|
+
// If this is a reference through an expression at the top level,
|
|
2117
|
+
// need to generate the expression because the expression is written
|
|
2118
|
+
// in the top level, this call is being used to generate the join.
|
|
2119
|
+
// Below the top level, the expression will have been written into
|
|
2120
|
+
// a join at the top level, and the name will exist.
|
|
2121
|
+
// ... not sure this is the right way to do this
|
|
2122
|
+
// ... the test for this is called "source repeated record containing an array"
|
|
2123
|
+
arrayExpression = qs.parent.sqlChildReference(qsDef.name, depth === 0 ? { result: this.rootResult, field: this } : undefined);
|
|
2124
|
+
}
|
|
2079
2125
|
// we need to generate primary key. If parent has a primary key combine
|
|
2080
2126
|
// console.log(ji.alias, fieldExpression, this.inNestedPipeline());
|
|
2081
|
-
s += `${this.parent.dialect.sqlUnnestAlias(
|
|
2127
|
+
s += `${this.parent.dialect.sqlUnnestAlias(arrayExpression, ji.alias, ji.getDialectFieldList(), ji.makeUniqueKey, (0, malloy_types_1.isScalarArray)(qsDef), this.inNestedPipeline())}\n`;
|
|
2082
2128
|
}
|
|
2083
2129
|
else if (qsDef.type === 'record') {
|
|
2084
2130
|
throw new Error('Internal Error: records should never appear in join trees');
|
|
@@ -2087,7 +2133,7 @@ class QueryQuery extends QueryField {
|
|
|
2087
2133
|
throw new Error(`Join type not implemented ${qs.structDef.type}`);
|
|
2088
2134
|
}
|
|
2089
2135
|
for (const childJoin of ji.children) {
|
|
2090
|
-
s += this.generateSQLJoinBlock(stageWriter, childJoin);
|
|
2136
|
+
s += this.generateSQLJoinBlock(stageWriter, childJoin, depth + 1);
|
|
2091
2137
|
}
|
|
2092
2138
|
return s;
|
|
2093
2139
|
}
|
|
@@ -2134,7 +2180,7 @@ class QueryQuery extends QueryField {
|
|
|
2134
2180
|
throw new Error('Internal Error, queries must start from a basetable');
|
|
2135
2181
|
}
|
|
2136
2182
|
for (const childJoin of ji.children) {
|
|
2137
|
-
s += this.generateSQLJoinBlock(stageWriter, childJoin);
|
|
2183
|
+
s += this.generateSQLJoinBlock(stageWriter, childJoin, 0);
|
|
2138
2184
|
}
|
|
2139
2185
|
return s;
|
|
2140
2186
|
}
|
|
@@ -2716,9 +2762,10 @@ class QueryQuery extends QueryField {
|
|
|
2716
2762
|
};
|
|
2717
2763
|
pipeline.shift();
|
|
2718
2764
|
for (const transform of pipeline) {
|
|
2719
|
-
const
|
|
2720
|
-
|
|
2721
|
-
|
|
2765
|
+
const parent = this.parent.parent
|
|
2766
|
+
? { struct: this.parent.parent }
|
|
2767
|
+
: { model: this.parent.getModel() };
|
|
2768
|
+
const s = new QueryStruct(structDef, undefined, parent, this.parent.prepareResultOptions);
|
|
2722
2769
|
const q = QueryQuery.makeQuery({ type: 'turtle', name: '~computeLastStage~', pipeline: [transform] }, s, stageWriter, this.isJoinedSubquery);
|
|
2723
2770
|
q.prepare(stageWriter);
|
|
2724
2771
|
lastStageName = q.generateSQL(stageWriter);
|
|
@@ -2761,7 +2808,7 @@ class QueryQueryIndexStage extends QueryQuery {
|
|
|
2761
2808
|
resultIndex,
|
|
2762
2809
|
type: 'result',
|
|
2763
2810
|
});
|
|
2764
|
-
if (field instanceof
|
|
2811
|
+
if (field instanceof AbstractQueryAtomic) {
|
|
2765
2812
|
this.addDependancies(resultStruct, field);
|
|
2766
2813
|
}
|
|
2767
2814
|
resultIndex++;
|
|
@@ -2876,7 +2923,7 @@ class QueryQueryRaw extends QueryQuery {
|
|
|
2876
2923
|
}
|
|
2877
2924
|
getResultStructDef() {
|
|
2878
2925
|
if (!(0, malloy_types_1.isSourceDef)(this.parent.structDef)) {
|
|
2879
|
-
throw new Error(`Result cannot
|
|
2926
|
+
throw new Error(`Result cannot be type ${this.parent.structDef.type}`);
|
|
2880
2927
|
}
|
|
2881
2928
|
return { ...this.parent.structDef, type: 'query_result' };
|
|
2882
2929
|
}
|
|
@@ -2906,10 +2953,9 @@ class QueryQueryIndex extends QueryQuery {
|
|
|
2906
2953
|
const stage = stageMap[stageRoot];
|
|
2907
2954
|
if (stage === undefined) {
|
|
2908
2955
|
const f = this.parent.nameMap.get(fref.path[0]);
|
|
2909
|
-
if (f instanceof
|
|
2910
|
-
|
|
2911
|
-
f.
|
|
2912
|
-
f.structDef.fields.length > 1) {
|
|
2956
|
+
if (f instanceof QueryFieldStruct &&
|
|
2957
|
+
f.fieldDef.join === 'many' &&
|
|
2958
|
+
f.fieldDef.fields.length > 1) {
|
|
2913
2959
|
const toStage = [fref];
|
|
2914
2960
|
stageMap[stageRoot] = toStage;
|
|
2915
2961
|
this.stages.push(toStage);
|
|
@@ -2978,18 +3024,39 @@ class QueryQueryIndex extends QueryQuery {
|
|
|
2978
3024
|
return ret;
|
|
2979
3025
|
}
|
|
2980
3026
|
}
|
|
2981
|
-
/** Structure object as it is used to build a query */
|
|
2982
3027
|
/*
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
3028
|
+
* The input to a query will always be a QueryStruct. A QueryStruct is also a namespace
|
|
3029
|
+
* for tracking joins, and so a QueryFieldStruct is a QueryField which has a QueryStruct.
|
|
3030
|
+
*
|
|
3031
|
+
* This is a result of it being impossible to inherit both from QueryStruct and QueryField
|
|
3032
|
+
* for array and record types.
|
|
3033
|
+
*/
|
|
3034
|
+
class QueryFieldStruct extends QueryField {
|
|
3035
|
+
constructor(jfd, sourceArguments, parent, prepareResultOptions, referenceId) {
|
|
3036
|
+
super(jfd, parent, referenceId);
|
|
3037
|
+
this.fieldDef = jfd;
|
|
3038
|
+
this.queryStruct = new QueryStruct(jfd, sourceArguments, { struct: parent }, prepareResultOptions);
|
|
3039
|
+
}
|
|
3040
|
+
/*
|
|
3041
|
+
* Proxy the field-like methods that QueryStruct implements, eventually
|
|
3042
|
+
* those probably should be in here ... I thought this would be important
|
|
3043
|
+
* but maybe it isn't, it doesn't fix the problem I am working on ...
|
|
3044
|
+
*/
|
|
3045
|
+
// mtoy todo review with lloyd if any of these are needed, had to NOT
|
|
3046
|
+
// do getIdentifier to pass a test, didn't stop to think why.
|
|
3047
|
+
// getIdentifier() {
|
|
3048
|
+
// return this.queryStruct.getIdentifier();
|
|
3049
|
+
// }
|
|
3050
|
+
getJoinableParent() {
|
|
3051
|
+
return this.queryStruct.getJoinableParent();
|
|
3052
|
+
}
|
|
3053
|
+
getFullOutputName() {
|
|
3054
|
+
return this.queryStruct.getFullOutputName();
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
/** Structure object as it is used to build a query */
|
|
3058
|
+
class QueryStruct {
|
|
3059
|
+
constructor(structDef, sourceArguments, parent, prepareResultOptions) {
|
|
2993
3060
|
this.structDef = structDef;
|
|
2994
3061
|
this.sourceArguments = sourceArguments;
|
|
2995
3062
|
this.prepareResultOptions = prepareResultOptions;
|
|
@@ -3014,6 +3081,9 @@ class QueryStruct extends QueryNode {
|
|
|
3014
3081
|
this.dialect = (0, dialect_1.getDialect)(structDef.dialect);
|
|
3015
3082
|
this.addFieldsFromFieldList(structDef.fields);
|
|
3016
3083
|
}
|
|
3084
|
+
informOfAliasValue(av) {
|
|
3085
|
+
this.recordAlias = av;
|
|
3086
|
+
}
|
|
3017
3087
|
maybeEmitParameterizedSourceUsage() {
|
|
3018
3088
|
var _a;
|
|
3019
3089
|
if ((0, malloy_types_1.isSourceDef)(this.structDef)) {
|
|
@@ -3076,15 +3146,15 @@ class QueryStruct extends QueryNode {
|
|
|
3076
3146
|
addFieldsFromFieldList(fields) {
|
|
3077
3147
|
for (const field of fields) {
|
|
3078
3148
|
const as = (0, malloy_types_1.getIdentifier)(field);
|
|
3079
|
-
if (
|
|
3080
|
-
this.addFieldToNameMap(as, new QueryStruct(field, undefined, { struct: this }, this.prepareResultOptions));
|
|
3081
|
-
}
|
|
3082
|
-
else if (field.type === 'turtle') {
|
|
3149
|
+
if (field.type === 'turtle') {
|
|
3083
3150
|
this.addFieldToNameMap(as, QueryQuery.makeQuery(field, this, undefined, false));
|
|
3084
3151
|
}
|
|
3085
|
-
else {
|
|
3152
|
+
else if ((0, malloy_types_1.isAtomic)(field) || (0, malloy_types_1.isJoinedSource)(field)) {
|
|
3086
3153
|
this.addFieldToNameMap(as, this.makeQueryField(field));
|
|
3087
3154
|
}
|
|
3155
|
+
else {
|
|
3156
|
+
throw new Error('mtoy did nit add field');
|
|
3157
|
+
}
|
|
3088
3158
|
}
|
|
3089
3159
|
// if we don't have distinct key yet for this struct, add it.
|
|
3090
3160
|
if (!this.nameMap.has('__distinct_key')) {
|
|
@@ -3133,15 +3203,47 @@ class QueryStruct extends QueryNode {
|
|
|
3133
3203
|
return this.getIdentifier();
|
|
3134
3204
|
}
|
|
3135
3205
|
}
|
|
3206
|
+
sqlChildReference(name, expand) {
|
|
3207
|
+
let parentRef = this.getSQLIdentifier();
|
|
3208
|
+
if (expand && (0, malloy_types_1.isAtomic)(this.structDef) && (0, malloy_types_1.hasExpression)(this.structDef)) {
|
|
3209
|
+
parentRef = expand.field.exprToSQL(expand.result, this, this.structDef.e);
|
|
3210
|
+
}
|
|
3211
|
+
let refType = 'table';
|
|
3212
|
+
if (this.structDef.type === 'record') {
|
|
3213
|
+
refType = 'record';
|
|
3214
|
+
}
|
|
3215
|
+
else if (this.structDef.type === 'array') {
|
|
3216
|
+
refType =
|
|
3217
|
+
this.structDef.elementTypeDef.type === 'record_element'
|
|
3218
|
+
? 'array[record]'
|
|
3219
|
+
: 'array[scalar]';
|
|
3220
|
+
}
|
|
3221
|
+
else if (this.structDef.type === 'nest_source') {
|
|
3222
|
+
refType = 'nest source';
|
|
3223
|
+
}
|
|
3224
|
+
const child = this.getChildByName(name);
|
|
3225
|
+
const childType = (child === null || child === void 0 ? void 0 : child.fieldDef.type) || 'unknown';
|
|
3226
|
+
return this.dialect.sqlFieldReference(parentRef, refType, name, childType);
|
|
3227
|
+
}
|
|
3136
3228
|
// return the name of the field in SQL
|
|
3137
3229
|
getIdentifier() {
|
|
3138
3230
|
// if it is the root table, use provided alias if we have one.
|
|
3139
3231
|
if ((0, malloy_types_1.isBaseTable)(this.structDef)) {
|
|
3140
3232
|
return 'base';
|
|
3141
3233
|
}
|
|
3234
|
+
// If this is a synthetic column, return the expression rather than the name
|
|
3235
|
+
// because the name will not exist. Only for records because the other types
|
|
3236
|
+
// will have joins and thus be in the namespace. We can't compute it here
|
|
3237
|
+
// because we don't have access to the Query to call exprToSQL.
|
|
3238
|
+
if (this.structDef.type === 'record' && (0, malloy_types_1.hasExpression)(this.structDef)) {
|
|
3239
|
+
if (this.recordAlias) {
|
|
3240
|
+
return this.recordAlias;
|
|
3241
|
+
}
|
|
3242
|
+
throw new Error('INTERNAL ERROR, record field alias not pre-computed');
|
|
3243
|
+
}
|
|
3142
3244
|
// if this is an inline object, include the parents alias.
|
|
3143
3245
|
if (this.structDef.type === 'record' && this.parent) {
|
|
3144
|
-
return
|
|
3246
|
+
return this.parent.sqlChildReference((0, malloy_types_1.getIdentifier)(this.structDef), undefined);
|
|
3145
3247
|
}
|
|
3146
3248
|
// we are somewhere in the join tree. Make sure the alias is unique.
|
|
3147
3249
|
return this.getAliasIdentifier();
|
|
@@ -3222,8 +3324,8 @@ class QueryStruct extends QueryNode {
|
|
|
3222
3324
|
}
|
|
3223
3325
|
}
|
|
3224
3326
|
for (const [, v] of this.nameMap) {
|
|
3225
|
-
if (v instanceof
|
|
3226
|
-
v.resolveQueryFields();
|
|
3327
|
+
if (v instanceof QueryFieldStruct) {
|
|
3328
|
+
v.queryStruct.resolveQueryFields();
|
|
3227
3329
|
}
|
|
3228
3330
|
}
|
|
3229
3331
|
}
|
|
@@ -3255,6 +3357,13 @@ class QueryStruct extends QueryNode {
|
|
|
3255
3357
|
/** makes a new queryable field object from a fieldDef */
|
|
3256
3358
|
makeQueryField(field, referenceId) {
|
|
3257
3359
|
switch (field.type) {
|
|
3360
|
+
case 'array':
|
|
3361
|
+
case 'record':
|
|
3362
|
+
case 'query_source':
|
|
3363
|
+
case 'table':
|
|
3364
|
+
case 'sql_select':
|
|
3365
|
+
case 'composite':
|
|
3366
|
+
return new QueryFieldStruct(field, undefined, this, this.prepareResultOptions);
|
|
3258
3367
|
case 'string':
|
|
3259
3368
|
return new QueryFieldString(field, this, referenceId);
|
|
3260
3369
|
case 'date':
|
|
@@ -3269,13 +3378,10 @@ class QueryStruct extends QueryNode {
|
|
|
3269
3378
|
return new QueryFieldJSON(field, this, referenceId);
|
|
3270
3379
|
case 'sql native':
|
|
3271
3380
|
return new QueryFieldUnsupported(field, this, referenceId);
|
|
3272
|
-
// case "reduce":
|
|
3273
|
-
// case "project":
|
|
3274
|
-
// case "index":
|
|
3275
3381
|
case 'turtle':
|
|
3276
|
-
return
|
|
3382
|
+
return QueryQuery.makeQuery(field, this, undefined, false);
|
|
3277
3383
|
default:
|
|
3278
|
-
throw new Error(`unknown field definition ${JSON.stringify(field)}`);
|
|
3384
|
+
throw new Error(`unknown field definition ${(JSON.stringify(field), undefined, 2)}`);
|
|
3279
3385
|
}
|
|
3280
3386
|
}
|
|
3281
3387
|
structSourceSQL(stageWriter) {
|
|
@@ -3323,35 +3429,43 @@ class QueryStruct extends QueryNode {
|
|
|
3323
3429
|
}
|
|
3324
3430
|
/** convert a path into a field reference */
|
|
3325
3431
|
getFieldByName(path) {
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3432
|
+
let found = undefined;
|
|
3433
|
+
let lookIn = this;
|
|
3434
|
+
let notFound = path[0];
|
|
3435
|
+
for (const n of path) {
|
|
3436
|
+
found = lookIn === null || lookIn === void 0 ? void 0 : lookIn.getChildByName(n);
|
|
3437
|
+
if (!found) {
|
|
3438
|
+
notFound = n;
|
|
3439
|
+
break;
|
|
3332
3440
|
}
|
|
3333
|
-
|
|
3334
|
-
|
|
3441
|
+
lookIn =
|
|
3442
|
+
found instanceof QueryFieldStruct ? found.queryStruct : undefined;
|
|
3443
|
+
}
|
|
3444
|
+
if (found === undefined) {
|
|
3445
|
+
const pathErr = path.length > 1 ? ` in ${path.join('.')}` : '';
|
|
3446
|
+
throw new Error(`${notFound} not found${pathErr}`);
|
|
3447
|
+
}
|
|
3448
|
+
return found;
|
|
3335
3449
|
}
|
|
3336
3450
|
// structs referenced in queries are converted to fields.
|
|
3337
3451
|
getQueryFieldByName(name) {
|
|
3338
3452
|
const field = this.getFieldByName(name);
|
|
3339
|
-
if (field instanceof
|
|
3453
|
+
if (field instanceof QueryFieldStruct) {
|
|
3340
3454
|
throw new Error(`Cannot reference ${name.join('.')} as a scalar'`);
|
|
3341
3455
|
}
|
|
3342
3456
|
return field;
|
|
3343
3457
|
}
|
|
3344
|
-
getQueryFieldReference(
|
|
3345
|
-
const field = this.getFieldByName(
|
|
3458
|
+
getQueryFieldReference(path, annotation) {
|
|
3459
|
+
const field = this.getFieldByName(path);
|
|
3346
3460
|
if (annotation) {
|
|
3347
3461
|
if (field.parent === undefined) {
|
|
3348
|
-
throw new Error('
|
|
3462
|
+
throw new Error('Inconcievable, field reference to orphaned query field');
|
|
3349
3463
|
}
|
|
3350
3464
|
// Made a field object from the source, but the annotations were computed by the compiler
|
|
3351
3465
|
// when it generated the reference, and has both the source and reference annotations included.
|
|
3352
|
-
if (field instanceof
|
|
3353
|
-
const newDef = { ...field.
|
|
3354
|
-
return new
|
|
3466
|
+
if (field instanceof QueryFieldStruct) {
|
|
3467
|
+
const newDef = { ...field.fieldDef, annotation };
|
|
3468
|
+
return new QueryFieldStruct(newDef, undefined, field.parent, {}, field.referenceId);
|
|
3355
3469
|
}
|
|
3356
3470
|
else {
|
|
3357
3471
|
const newDef = { ...field.fieldDef, annotation };
|
|
@@ -3361,29 +3475,30 @@ class QueryStruct extends QueryNode {
|
|
|
3361
3475
|
return field;
|
|
3362
3476
|
}
|
|
3363
3477
|
getDimensionOrMeasureByName(name) {
|
|
3364
|
-
const
|
|
3365
|
-
if (
|
|
3366
|
-
|
|
3478
|
+
const field = this.getFieldByName(name);
|
|
3479
|
+
if (!field.isAtomic()) {
|
|
3480
|
+
throw new Error(`${name} is not an atomic field? Inconceivable!`);
|
|
3367
3481
|
}
|
|
3368
|
-
|
|
3482
|
+
return field;
|
|
3369
3483
|
}
|
|
3370
3484
|
/** returns a query object for the given name */
|
|
3371
3485
|
getDimensionByName(name) {
|
|
3372
|
-
const
|
|
3373
|
-
if (
|
|
3374
|
-
return
|
|
3486
|
+
const field = this.getFieldByName(name);
|
|
3487
|
+
if (field.isAtomic() && isScalarField(field)) {
|
|
3488
|
+
return field;
|
|
3375
3489
|
}
|
|
3376
3490
|
throw new Error(`${name} is not an atomic scalar field? Inconceivable!`);
|
|
3377
3491
|
}
|
|
3378
3492
|
/** returns a query object for the given name */
|
|
3379
3493
|
getStructByName(name) {
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
return struct;
|
|
3494
|
+
if (name.length === 0) {
|
|
3495
|
+
return this;
|
|
3383
3496
|
}
|
|
3384
|
-
|
|
3385
|
-
|
|
3497
|
+
const struct = this.getFieldByName(name);
|
|
3498
|
+
if (struct instanceof QueryFieldStruct) {
|
|
3499
|
+
return struct.queryStruct;
|
|
3386
3500
|
}
|
|
3501
|
+
throw new Error(`Error: Path to structure not found '${name.join('.')}'`);
|
|
3387
3502
|
}
|
|
3388
3503
|
getDistinctKey() {
|
|
3389
3504
|
if (this.structDef.type !== 'record') {
|
|
@@ -3532,7 +3647,7 @@ class QueryModel {
|
|
|
3532
3647
|
const struct = this.getStructByName(explore);
|
|
3533
3648
|
let indexStar = [];
|
|
3534
3649
|
for (const [fn, fv] of struct.nameMap) {
|
|
3535
|
-
if (!(fv instanceof
|
|
3650
|
+
if (!(fv instanceof QueryFieldStruct)) {
|
|
3536
3651
|
if (isScalarField(fv) && fv.includeInWildcard()) {
|
|
3537
3652
|
indexStar.push({ type: 'fieldref', path: [fn] });
|
|
3538
3653
|
}
|