@devrev/meerkat-core 0.0.84 → 0.0.85
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/package.json +1 -1
- package/src/ast-serializer/ast-serializer.d.ts +1 -0
- package/src/ast-serializer/ast-serializer.js +12 -0
- package/src/ast-serializer/ast-serializer.js.map +1 -0
- package/src/ast-validator/dimension-validator.d.ts +10 -0
- package/src/ast-validator/dimension-validator.js +54 -0
- package/src/ast-validator/dimension-validator.js.map +1 -0
- package/src/ast-validator/index.d.ts +3 -0
- package/src/ast-validator/index.js +21 -0
- package/src/ast-validator/index.js.map +1 -0
- package/src/ast-validator/measure-validator.d.ts +11 -0
- package/src/ast-validator/measure-validator.js +162 -0
- package/src/ast-validator/measure-validator.js.map +1 -0
- package/src/ast-validator/tests/test-data.d.ts +2115 -0
- package/src/ast-validator/tests/test-data.js +2060 -0
- package/src/ast-validator/tests/test-data.js.map +1 -0
- package/src/ast-validator/types.d.ts +8 -0
- package/src/ast-validator/types.js +3 -0
- package/src/ast-validator/types.js.map +1 -0
- package/src/ast-validator/utils.d.ts +4 -0
- package/src/ast-validator/utils.js +35 -0
- package/src/ast-validator/utils.js.map +1 -0
- package/src/cube-filter-transformer/not/not.d.ts +2 -2
- package/src/cube-filter-transformer/not/not.js.map +1 -1
- package/src/index.d.ts +4 -1
- package/src/index.js +3 -0
- package/src/index.js.map +1 -1
- package/src/types/duckdb-serialization-types/serialization/ParsedExpression.d.ts +17 -0
- package/src/types/duckdb-serialization-types/serialization/ParsedExpression.js.map +1 -1
- package/src/types/utils.d.ts +19 -0
- package/src/types/utils.js +108 -0
- package/src/types/utils.js.map +1 -0
- package/src/utils/base-ast.js +2 -3
- package/src/utils/base-ast.js.map +1 -1
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const astSerializerQuery: (query: string) => string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "astSerializerQuery", {
|
|
3
|
+
enumerable: true,
|
|
4
|
+
get: function() {
|
|
5
|
+
return astSerializerQuery;
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
const astSerializerQuery = (query)=>{
|
|
9
|
+
return `SELECT json_serialize_sql('${query}')`;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=ast-serializer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../meerkat-core/src/ast-serializer/ast-serializer.ts"],"sourcesContent":["export const astSerializerQuery = (query: string) => {\n return `SELECT json_serialize_sql('${query}')`;\n};\n"],"names":["astSerializerQuery","query"],"mappings":";+BAAaA;;;eAAAA;;;AAAN,MAAMA,qBAAqB,CAACC;IACjC,OAAO,CAAC,2BAA2B,EAAEA,MAAM,EAAE,CAAC;AAChD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ParsedExpression } from '../types/duckdb-serialization-types';
|
|
2
|
+
import { ParsedSerialization } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Validates an individual expression node
|
|
5
|
+
*/
|
|
6
|
+
export declare const validateExpressionNode: (node: ParsedExpression, validFunctions: Set<string>) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Validates if the parsed serialization represents a valid dimension
|
|
9
|
+
*/
|
|
10
|
+
export declare const validateDimension: (parsedSerialization: ParsedSerialization, validFunctions: string[]) => boolean;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
function _export(target, all) {
|
|
3
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
4
|
+
enumerable: true,
|
|
5
|
+
get: all[name]
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
_export(exports, {
|
|
9
|
+
validateExpressionNode: function() {
|
|
10
|
+
return validateExpressionNode;
|
|
11
|
+
},
|
|
12
|
+
validateDimension: function() {
|
|
13
|
+
return validateDimension;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const _utils = require("../types/utils");
|
|
17
|
+
const _utils1 = require("./utils");
|
|
18
|
+
const validateExpressionNode = (node, validFunctions)=>{
|
|
19
|
+
// Column references and value constants
|
|
20
|
+
if ((0, _utils.isColumnRefExpression)(node) || (0, _utils.isConstantExpression)(node)) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
// Cast expression
|
|
24
|
+
if ((0, _utils.isCastExpression)(node)) {
|
|
25
|
+
return validateExpressionNode(node.child, validFunctions);
|
|
26
|
+
}
|
|
27
|
+
// Operator expression
|
|
28
|
+
if ((0, _utils.isOperatorExpression)(node)) {
|
|
29
|
+
return node.children.every((child)=>validateExpressionNode(child, validFunctions));
|
|
30
|
+
}
|
|
31
|
+
// Function expression
|
|
32
|
+
if ((0, _utils.isFunctionExpression)(node)) {
|
|
33
|
+
if (!validFunctions.has(node.function_name)) {
|
|
34
|
+
throw new Error(`Invalid function: ${node.function_name}`);
|
|
35
|
+
}
|
|
36
|
+
return node.children.every((child)=>validateExpressionNode(child, validFunctions));
|
|
37
|
+
}
|
|
38
|
+
// Case expression
|
|
39
|
+
if ((0, _utils.isCaseExpression)(node)) {
|
|
40
|
+
return node.case_checks.every((check)=>validateExpressionNode(check.then_expr, validFunctions)) && validateExpressionNode(node.else_expr, validFunctions);
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`Invalid expression type: ${node.type}`);
|
|
43
|
+
};
|
|
44
|
+
const validateDimension = (parsedSerialization, validFunctions)=>{
|
|
45
|
+
const node = (0, _utils1.getSelectNode)(parsedSerialization);
|
|
46
|
+
const validFunctionSet = new Set(validFunctions);
|
|
47
|
+
// Validate the expression
|
|
48
|
+
if (validateExpressionNode(node, validFunctionSet)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
throw new Error('Expression contains invalid functions or operators');
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=dimension-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../meerkat-core/src/ast-validator/dimension-validator.ts"],"sourcesContent":["import { ParsedExpression } from '../types/duckdb-serialization-types';\nimport {\n isCaseExpression,\n isCastExpression,\n isColumnRefExpression,\n isConstantExpression,\n isFunctionExpression,\n isOperatorExpression,\n} from '../types/utils';\nimport { ParsedSerialization } from './types';\nimport { getSelectNode } from './utils';\n\n/**\n * Validates an individual expression node\n */\nexport const validateExpressionNode = (\n node: ParsedExpression,\n validFunctions: Set<string>\n): boolean => {\n // Column references and value constants\n if (isColumnRefExpression(node) || isConstantExpression(node)) {\n return true;\n }\n\n // Cast expression\n if (isCastExpression(node)) {\n return validateExpressionNode(node.child, validFunctions);\n }\n\n // Operator expression\n if (isOperatorExpression(node)) {\n return node.children.every((child) =>\n validateExpressionNode(child, validFunctions)\n );\n }\n\n // Function expression\n if (isFunctionExpression(node)) {\n if (!validFunctions.has(node.function_name)) {\n throw new Error(`Invalid function: ${node.function_name}`);\n }\n return node.children.every((child) =>\n validateExpressionNode(child, validFunctions)\n );\n }\n\n // Case expression\n if (isCaseExpression(node)) {\n return (\n node.case_checks.every((check) =>\n validateExpressionNode(check.then_expr, validFunctions)\n ) && validateExpressionNode(node.else_expr, validFunctions)\n );\n }\n\n throw new Error(`Invalid expression type: ${node.type}`);\n};\n\n/**\n * Validates if the parsed serialization represents a valid dimension\n */\nexport const validateDimension = (\n parsedSerialization: ParsedSerialization,\n validFunctions: string[]\n): boolean => {\n const node = getSelectNode(parsedSerialization);\n\n const validFunctionSet = new Set(validFunctions);\n\n // Validate the expression\n if (validateExpressionNode(node, validFunctionSet)) {\n return true;\n }\n\n throw new Error('Expression contains invalid functions or operators');\n};\n"],"names":["validateExpressionNode","validateDimension","node","validFunctions","isColumnRefExpression","isConstantExpression","isCastExpression","child","isOperatorExpression","children","every","isFunctionExpression","has","function_name","Error","isCaseExpression","case_checks","check","then_expr","else_expr","type","parsedSerialization","getSelectNode","validFunctionSet","Set"],"mappings":";;;;;;;;IAeaA,sBAAsB;eAAtBA;;IA8CAC,iBAAiB;eAAjBA;;;uBArDN;wBAEuB;AAKvB,MAAMD,yBAAyB,CACpCE,MACAC;IAEA,wCAAwC;IACxC,IAAIC,IAAAA,4BAAqB,EAACF,SAASG,IAAAA,2BAAoB,EAACH,OAAO;QAC7D,OAAO;IACT;IAEA,kBAAkB;IAClB,IAAII,IAAAA,uBAAgB,EAACJ,OAAO;QAC1B,OAAOF,uBAAuBE,KAAKK,KAAK,EAAEJ;IAC5C;IAEA,sBAAsB;IACtB,IAAIK,IAAAA,2BAAoB,EAACN,OAAO;QAC9B,OAAOA,KAAKO,QAAQ,CAACC,KAAK,CAAC,CAACH,QAC1BP,uBAAuBO,OAAOJ;IAElC;IAEA,sBAAsB;IACtB,IAAIQ,IAAAA,2BAAoB,EAACT,OAAO;QAC9B,IAAI,CAACC,eAAeS,GAAG,CAACV,KAAKW,aAAa,GAAG;YAC3C,MAAM,IAAIC,MAAM,CAAC,kBAAkB,EAAEZ,KAAKW,aAAa,CAAC,CAAC;QAC3D;QACA,OAAOX,KAAKO,QAAQ,CAACC,KAAK,CAAC,CAACH,QAC1BP,uBAAuBO,OAAOJ;IAElC;IAEA,kBAAkB;IAClB,IAAIY,IAAAA,uBAAgB,EAACb,OAAO;QAC1B,OACEA,KAAKc,WAAW,CAACN,KAAK,CAAC,CAACO,QACtBjB,uBAAuBiB,MAAMC,SAAS,EAAEf,oBACrCH,uBAAuBE,KAAKiB,SAAS,EAAEhB;IAEhD;IAEA,MAAM,IAAIW,MAAM,CAAC,yBAAyB,EAAEZ,KAAKkB,IAAI,CAAC,CAAC;AACzD;AAKO,MAAMnB,oBAAoB,CAC/BoB,qBACAlB;IAEA,MAAMD,OAAOoB,IAAAA,qBAAa,EAACD;IAE3B,MAAME,mBAAmB,IAAIC,IAAIrB;IAEjC,0BAA0B;IAC1B,IAAIH,uBAAuBE,MAAMqB,mBAAmB;QAClD,OAAO;IACT;IAEA,MAAM,IAAIT,MAAM;AAClB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
function _export(target, all) {
|
|
3
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
4
|
+
enumerable: true,
|
|
5
|
+
get: all[name]
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
_export(exports, {
|
|
9
|
+
validateDimension: function() {
|
|
10
|
+
return _dimensionvalidator.validateDimension;
|
|
11
|
+
},
|
|
12
|
+
validateMeasure: function() {
|
|
13
|
+
return _measurevalidator.validateMeasure;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const _export_star = require("@swc/helpers/_/_export_star");
|
|
17
|
+
const _dimensionvalidator = require("./dimension-validator");
|
|
18
|
+
const _measurevalidator = require("./measure-validator");
|
|
19
|
+
_export_star._(require("./types"), exports);
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../meerkat-core/src/ast-validator/index.ts"],"sourcesContent":["export { validateDimension } from './dimension-validator';\nexport { validateMeasure } from './measure-validator';\nexport * from './types';\n"],"names":["validateDimension","validateMeasure"],"mappings":";;;;;;;;IAASA,iBAAiB;eAAjBA,qCAAiB;;IACjBC,eAAe;eAAfA,iCAAe;;;;oCADU;kCACF;uBAClB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ParsedExpression } from '../types/duckdb-serialization-types';
|
|
2
|
+
import { ParsedSerialization } from './types';
|
|
3
|
+
export declare const validateExpressionNode: ({ node, validFunctions, parentNode, validScalarFunctions, hasAggregation, }: {
|
|
4
|
+
node: ParsedExpression;
|
|
5
|
+
validFunctions: Set<string>;
|
|
6
|
+
parentNode: ParsedExpression | null;
|
|
7
|
+
hasAggregation?: boolean | undefined;
|
|
8
|
+
validScalarFunctions: Set<string>;
|
|
9
|
+
}) => boolean;
|
|
10
|
+
export declare const containsAggregation: (node: ParsedExpression, validFunctions: Set<string>) => boolean;
|
|
11
|
+
export declare const validateMeasure: (parsedSerialization: ParsedSerialization, validFunctions: string[], validScalarFunctions: string[]) => boolean;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
function _export(target, all) {
|
|
3
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
4
|
+
enumerable: true,
|
|
5
|
+
get: all[name]
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
_export(exports, {
|
|
9
|
+
validateExpressionNode: function() {
|
|
10
|
+
return validateExpressionNode;
|
|
11
|
+
},
|
|
12
|
+
containsAggregation: function() {
|
|
13
|
+
return containsAggregation;
|
|
14
|
+
},
|
|
15
|
+
validateMeasure: function() {
|
|
16
|
+
return validateMeasure;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _utils = require("../types/utils");
|
|
20
|
+
const _utils1 = require("./utils");
|
|
21
|
+
const validateExpressionNode = ({ node, validFunctions, parentNode, validScalarFunctions, hasAggregation = false })=>{
|
|
22
|
+
// Base cases for column references and constants
|
|
23
|
+
if ((0, _utils.isColumnRefExpression)(node) || (0, _utils.isConstantExpression)(node)) {
|
|
24
|
+
// Allow column references inside aggregation functions
|
|
25
|
+
return !!parentNode;
|
|
26
|
+
}
|
|
27
|
+
// Check for valid aggregation functions
|
|
28
|
+
if ((0, _utils.isFunctionExpression)(node) || (0, _utils.isWindowExpression)(node)) {
|
|
29
|
+
// count_star don't have children
|
|
30
|
+
if (node.function_name === 'count_star') return true;
|
|
31
|
+
// This is a valid aggregation function - verify its children don't contain nested aggregations
|
|
32
|
+
if (validFunctions.has(node.function_name)) {
|
|
33
|
+
return node.children.some((child)=>validateExpressionNode({
|
|
34
|
+
node: child,
|
|
35
|
+
validFunctions,
|
|
36
|
+
parentNode: node,
|
|
37
|
+
validScalarFunctions
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
// For non-aggregation functions
|
|
41
|
+
if (validScalarFunctions.has(node.function_name)) {
|
|
42
|
+
return node.children.some((child)=>{
|
|
43
|
+
return validateExpressionNode({
|
|
44
|
+
node: child,
|
|
45
|
+
validFunctions,
|
|
46
|
+
parentNode: node,
|
|
47
|
+
validScalarFunctions
|
|
48
|
+
}) && (containsAggregation(child, validFunctions) || hasAggregation);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Invalid function type: ${node.function_name}`);
|
|
52
|
+
}
|
|
53
|
+
// Operator expression
|
|
54
|
+
if ((0, _utils.isOperatorExpression)(node)) {
|
|
55
|
+
return node.children.some((child)=>validateExpressionNode({
|
|
56
|
+
node: child,
|
|
57
|
+
validFunctions,
|
|
58
|
+
parentNode,
|
|
59
|
+
validScalarFunctions
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
// Cast expression
|
|
63
|
+
if ((0, _utils.isCastExpression)(node)) {
|
|
64
|
+
return validateExpressionNode({
|
|
65
|
+
node: node.child,
|
|
66
|
+
validFunctions,
|
|
67
|
+
parentNode,
|
|
68
|
+
validScalarFunctions
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Case expression
|
|
72
|
+
if ((0, _utils.isCaseExpression)(node)) {
|
|
73
|
+
const checksValid = node.case_checks.every((caseCheck)=>{
|
|
74
|
+
// WHEN conditions cannot contain aggregations
|
|
75
|
+
const whenValid = !containsAggregation(caseCheck.when_expr, validFunctions);
|
|
76
|
+
// THEN expressions must be valid aggregations or contain no aggregations
|
|
77
|
+
const thenValid = validateExpressionNode({
|
|
78
|
+
node: caseCheck.then_expr,
|
|
79
|
+
validFunctions,
|
|
80
|
+
parentNode: node,
|
|
81
|
+
validScalarFunctions
|
|
82
|
+
}) || !containsAggregation(caseCheck.then_expr, validFunctions);
|
|
83
|
+
return whenValid && thenValid;
|
|
84
|
+
});
|
|
85
|
+
const elseValid = validateExpressionNode({
|
|
86
|
+
node: node.else_expr,
|
|
87
|
+
validFunctions,
|
|
88
|
+
parentNode: node,
|
|
89
|
+
validScalarFunctions
|
|
90
|
+
}) || !containsAggregation(node.else_expr, validFunctions);
|
|
91
|
+
return checksValid && elseValid;
|
|
92
|
+
}
|
|
93
|
+
// Subquery expression
|
|
94
|
+
if ((0, _utils.isSubqueryExpression)(node) && (0, _utils.isSelectNode)(node.subquery.node)) {
|
|
95
|
+
return node.subquery.node.select_list.every((node)=>{
|
|
96
|
+
return validateExpressionNode({
|
|
97
|
+
node,
|
|
98
|
+
validFunctions,
|
|
99
|
+
parentNode,
|
|
100
|
+
validScalarFunctions
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Window expression
|
|
105
|
+
if ((0, _utils.isWindowExpression)(node)) {
|
|
106
|
+
return node.children.every((node)=>{
|
|
107
|
+
return validateExpressionNode({
|
|
108
|
+
node,
|
|
109
|
+
validFunctions,
|
|
110
|
+
parentNode,
|
|
111
|
+
validScalarFunctions
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
throw new Error(`Invalid expression type: ${node.type}`);
|
|
116
|
+
};
|
|
117
|
+
const containsAggregation = (node, validFunctions)=>{
|
|
118
|
+
if (!node) return false;
|
|
119
|
+
// Function expression
|
|
120
|
+
if ((0, _utils.isFunctionExpression)(node) || (0, _utils.isWindowExpression)(node)) {
|
|
121
|
+
return validFunctions.has(node.function_name) || node.children.some((child)=>containsAggregation(child, validFunctions));
|
|
122
|
+
}
|
|
123
|
+
// Case expression
|
|
124
|
+
if ((0, _utils.isCaseExpression)(node)) {
|
|
125
|
+
return node.case_checks.some((check)=>containsAggregation(check.when_expr, validFunctions) || containsAggregation(check.then_expr, validFunctions)) || containsAggregation(node.else_expr, validFunctions);
|
|
126
|
+
}
|
|
127
|
+
// Operator expression
|
|
128
|
+
if ((0, _utils.isOperatorExpression)(node)) {
|
|
129
|
+
return node.children.some((child)=>containsAggregation(child, validFunctions));
|
|
130
|
+
}
|
|
131
|
+
if ((0, _utils.isCastExpression)(node)) {
|
|
132
|
+
return containsAggregation(node.child, validFunctions);
|
|
133
|
+
}
|
|
134
|
+
// Window expression
|
|
135
|
+
if ((0, _utils.isWindowExpression)(node)) {
|
|
136
|
+
return node.children.some((child)=>containsAggregation(child, validFunctions));
|
|
137
|
+
}
|
|
138
|
+
// Subquery expression
|
|
139
|
+
if ((0, _utils.isSubqueryExpression)(node) && (0, _utils.isSelectNode)(node.subquery.node)) {
|
|
140
|
+
return node.subquery.node.select_list.every((node)=>{
|
|
141
|
+
return containsAggregation(node, validFunctions);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
};
|
|
146
|
+
const validateMeasure = (parsedSerialization, validFunctions, validScalarFunctions)=>{
|
|
147
|
+
const node = (0, _utils1.getSelectNode)(parsedSerialization);
|
|
148
|
+
const validFunctionSet = new Set(validFunctions);
|
|
149
|
+
const validScalarFunctionSet = new Set(validScalarFunctions);
|
|
150
|
+
// Validate the expression
|
|
151
|
+
if (validateExpressionNode({
|
|
152
|
+
node: node,
|
|
153
|
+
validFunctions: validFunctionSet,
|
|
154
|
+
parentNode: null,
|
|
155
|
+
validScalarFunctions: validScalarFunctionSet
|
|
156
|
+
})) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
throw new Error('Expression contains invalid functions or operators');
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=measure-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../meerkat-core/src/ast-validator/measure-validator.ts"],"sourcesContent":["import { ParsedExpression } from '../types/duckdb-serialization-types';\nimport {\n isCaseExpression,\n isCastExpression,\n isColumnRefExpression,\n isConstantExpression,\n isFunctionExpression,\n isOperatorExpression,\n isSelectNode,\n isSubqueryExpression,\n isWindowExpression,\n} from '../types/utils';\nimport { ParsedSerialization } from './types';\nimport { getSelectNode } from './utils';\n\nexport const validateExpressionNode = ({\n node,\n validFunctions,\n parentNode,\n validScalarFunctions,\n hasAggregation = false,\n}: {\n node: ParsedExpression;\n validFunctions: Set<string>;\n parentNode: ParsedExpression | null;\n hasAggregation?: boolean;\n validScalarFunctions: Set<string>;\n}): boolean => {\n // Base cases for column references and constants\n if (isColumnRefExpression(node) || isConstantExpression(node)) {\n // Allow column references inside aggregation functions\n return !!parentNode;\n }\n\n // Check for valid aggregation functions\n if (isFunctionExpression(node) || isWindowExpression(node)) {\n // count_star don't have children\n if (node.function_name === 'count_star') return true;\n\n // This is a valid aggregation function - verify its children don't contain nested aggregations\n if (validFunctions.has(node.function_name)) {\n return node.children.some((child) =>\n validateExpressionNode({\n node: child,\n validFunctions,\n parentNode: node,\n validScalarFunctions,\n })\n );\n }\n // For non-aggregation functions\n if (validScalarFunctions.has(node.function_name)) {\n return node.children.some((child) => {\n return (\n validateExpressionNode({\n node: child,\n validFunctions,\n parentNode: node,\n validScalarFunctions,\n }) &&\n (containsAggregation(child, validFunctions) || hasAggregation)\n );\n });\n }\n\n throw new Error(`Invalid function type: ${node.function_name}`);\n }\n\n // Operator expression\n if (isOperatorExpression(node)) {\n return node.children.some((child) =>\n validateExpressionNode({\n node: child,\n validFunctions,\n parentNode,\n validScalarFunctions,\n })\n );\n }\n\n // Cast expression\n if (isCastExpression(node)) {\n return validateExpressionNode({\n node: node.child,\n validFunctions,\n parentNode,\n validScalarFunctions,\n });\n }\n\n // Case expression\n if (isCaseExpression(node)) {\n const checksValid = node.case_checks.every((caseCheck) => {\n // WHEN conditions cannot contain aggregations\n const whenValid = !containsAggregation(\n caseCheck.when_expr,\n validFunctions\n );\n\n // THEN expressions must be valid aggregations or contain no aggregations\n const thenValid =\n validateExpressionNode({\n node: caseCheck.then_expr,\n validFunctions,\n parentNode: node,\n validScalarFunctions,\n }) || !containsAggregation(caseCheck.then_expr, validFunctions);\n return whenValid && thenValid;\n });\n\n const elseValid =\n validateExpressionNode({\n node: node.else_expr,\n validFunctions,\n parentNode: node,\n validScalarFunctions,\n }) || !containsAggregation(node.else_expr, validFunctions);\n\n return checksValid && elseValid;\n }\n\n // Subquery expression\n if (isSubqueryExpression(node) && isSelectNode(node.subquery.node)) {\n return node.subquery.node.select_list.every((node) => {\n return validateExpressionNode({\n node,\n validFunctions,\n parentNode,\n validScalarFunctions,\n });\n });\n }\n\n // Window expression\n if (isWindowExpression(node)) {\n return node.children.every((node) => {\n return validateExpressionNode({\n node,\n validFunctions,\n parentNode,\n validScalarFunctions,\n });\n });\n }\n\n throw new Error(`Invalid expression type: ${node.type}`);\n};\n\nexport const containsAggregation = (\n node: ParsedExpression,\n validFunctions: Set<string>\n): boolean => {\n if (!node) return false;\n\n // Function expression\n if (isFunctionExpression(node) || isWindowExpression(node)) {\n return (\n validFunctions.has(node.function_name) ||\n node.children.some((child) => containsAggregation(child, validFunctions))\n );\n }\n\n // Case expression\n if (isCaseExpression(node)) {\n return (\n node.case_checks.some(\n (check) =>\n containsAggregation(check.when_expr, validFunctions) ||\n containsAggregation(check.then_expr, validFunctions)\n ) || containsAggregation(node.else_expr, validFunctions)\n );\n }\n\n // Operator expression\n if (isOperatorExpression(node)) {\n return node.children.some((child) =>\n containsAggregation(child, validFunctions)\n );\n }\n\n if (isCastExpression(node)) {\n return containsAggregation(node.child, validFunctions);\n }\n\n // Window expression\n if (isWindowExpression(node)) {\n return node.children.some((child) =>\n containsAggregation(child, validFunctions)\n );\n }\n\n // Subquery expression\n if (isSubqueryExpression(node) && isSelectNode(node.subquery.node)) {\n return node.subquery.node.select_list.every((node) => {\n return containsAggregation(node, validFunctions);\n });\n }\n\n return false;\n};\n\nexport const validateMeasure = (\n parsedSerialization: ParsedSerialization,\n validFunctions: string[],\n validScalarFunctions: string[]\n): boolean => {\n const node = getSelectNode(parsedSerialization);\n\n const validFunctionSet = new Set(validFunctions);\n const validScalarFunctionSet = new Set(validScalarFunctions);\n\n // Validate the expression\n if (\n validateExpressionNode({\n node: node,\n validFunctions: validFunctionSet,\n parentNode: null,\n validScalarFunctions: validScalarFunctionSet,\n })\n ) {\n return true;\n }\n\n throw new Error('Expression contains invalid functions or operators');\n};\n"],"names":["validateExpressionNode","containsAggregation","validateMeasure","node","validFunctions","parentNode","validScalarFunctions","hasAggregation","isColumnRefExpression","isConstantExpression","isFunctionExpression","isWindowExpression","function_name","has","children","some","child","Error","isOperatorExpression","isCastExpression","isCaseExpression","checksValid","case_checks","every","caseCheck","whenValid","when_expr","thenValid","then_expr","elseValid","else_expr","isSubqueryExpression","isSelectNode","subquery","select_list","type","check","parsedSerialization","getSelectNode","validFunctionSet","Set","validScalarFunctionSet"],"mappings":";;;;;;;;IAeaA,sBAAsB;eAAtBA;;IAqIAC,mBAAmB;eAAnBA;;IAqDAC,eAAe;eAAfA;;;uBA9LN;wBAEuB;AAEvB,MAAMF,yBAAyB,CAAC,EACrCG,IAAI,EACJC,cAAc,EACdC,UAAU,EACVC,oBAAoB,EACpBC,iBAAiB,KAAK,EAOvB;IACC,iDAAiD;IACjD,IAAIC,IAAAA,4BAAqB,EAACL,SAASM,IAAAA,2BAAoB,EAACN,OAAO;QAC7D,uDAAuD;QACvD,OAAO,CAAC,CAACE;IACX;IAEA,wCAAwC;IACxC,IAAIK,IAAAA,2BAAoB,EAACP,SAASQ,IAAAA,yBAAkB,EAACR,OAAO;QAC1D,iCAAiC;QACjC,IAAIA,KAAKS,aAAa,KAAK,cAAc,OAAO;QAEhD,+FAA+F;QAC/F,IAAIR,eAAeS,GAAG,CAACV,KAAKS,aAAa,GAAG;YAC1C,OAAOT,KAAKW,QAAQ,CAACC,IAAI,CAAC,CAACC,QACzBhB,uBAAuB;oBACrBG,MAAMa;oBACNZ;oBACAC,YAAYF;oBACZG;gBACF;QAEJ;QACA,gCAAgC;QAChC,IAAIA,qBAAqBO,GAAG,CAACV,KAAKS,aAAa,GAAG;YAChD,OAAOT,KAAKW,QAAQ,CAACC,IAAI,CAAC,CAACC;gBACzB,OACEhB,uBAAuB;oBACrBG,MAAMa;oBACNZ;oBACAC,YAAYF;oBACZG;gBACF,MACCL,CAAAA,oBAAoBe,OAAOZ,mBAAmBG,cAAa;YAEhE;QACF;QAEA,MAAM,IAAIU,MAAM,CAAC,uBAAuB,EAAEd,KAAKS,aAAa,CAAC,CAAC;IAChE;IAEA,sBAAsB;IACtB,IAAIM,IAAAA,2BAAoB,EAACf,OAAO;QAC9B,OAAOA,KAAKW,QAAQ,CAACC,IAAI,CAAC,CAACC,QACzBhB,uBAAuB;gBACrBG,MAAMa;gBACNZ;gBACAC;gBACAC;YACF;IAEJ;IAEA,kBAAkB;IAClB,IAAIa,IAAAA,uBAAgB,EAAChB,OAAO;QAC1B,OAAOH,uBAAuB;YAC5BG,MAAMA,KAAKa,KAAK;YAChBZ;YACAC;YACAC;QACF;IACF;IAEA,kBAAkB;IAClB,IAAIc,IAAAA,uBAAgB,EAACjB,OAAO;QAC1B,MAAMkB,cAAclB,KAAKmB,WAAW,CAACC,KAAK,CAAC,CAACC;YAC1C,8CAA8C;YAC9C,MAAMC,YAAY,CAACxB,oBACjBuB,UAAUE,SAAS,EACnBtB;YAGF,yEAAyE;YACzE,MAAMuB,YACJ3B,uBAAuB;gBACrBG,MAAMqB,UAAUI,SAAS;gBACzBxB;gBACAC,YAAYF;gBACZG;YACF,MAAM,CAACL,oBAAoBuB,UAAUI,SAAS,EAAExB;YAClD,OAAOqB,aAAaE;QACtB;QAEA,MAAME,YACJ7B,uBAAuB;YACrBG,MAAMA,KAAK2B,SAAS;YACpB1B;YACAC,YAAYF;YACZG;QACF,MAAM,CAACL,oBAAoBE,KAAK2B,SAAS,EAAE1B;QAE7C,OAAOiB,eAAeQ;IACxB;IAEA,sBAAsB;IACtB,IAAIE,IAAAA,2BAAoB,EAAC5B,SAAS6B,IAAAA,mBAAY,EAAC7B,KAAK8B,QAAQ,CAAC9B,IAAI,GAAG;QAClE,OAAOA,KAAK8B,QAAQ,CAAC9B,IAAI,CAAC+B,WAAW,CAACX,KAAK,CAAC,CAACpB;YAC3C,OAAOH,uBAAuB;gBAC5BG;gBACAC;gBACAC;gBACAC;YACF;QACF;IACF;IAEA,oBAAoB;IACpB,IAAIK,IAAAA,yBAAkB,EAACR,OAAO;QAC5B,OAAOA,KAAKW,QAAQ,CAACS,KAAK,CAAC,CAACpB;YAC1B,OAAOH,uBAAuB;gBAC5BG;gBACAC;gBACAC;gBACAC;YACF;QACF;IACF;IAEA,MAAM,IAAIW,MAAM,CAAC,yBAAyB,EAAEd,KAAKgC,IAAI,CAAC,CAAC;AACzD;AAEO,MAAMlC,sBAAsB,CACjCE,MACAC;IAEA,IAAI,CAACD,MAAM,OAAO;IAElB,sBAAsB;IACtB,IAAIO,IAAAA,2BAAoB,EAACP,SAASQ,IAAAA,yBAAkB,EAACR,OAAO;QAC1D,OACEC,eAAeS,GAAG,CAACV,KAAKS,aAAa,KACrCT,KAAKW,QAAQ,CAACC,IAAI,CAAC,CAACC,QAAUf,oBAAoBe,OAAOZ;IAE7D;IAEA,kBAAkB;IAClB,IAAIgB,IAAAA,uBAAgB,EAACjB,OAAO;QAC1B,OACEA,KAAKmB,WAAW,CAACP,IAAI,CACnB,CAACqB,QACCnC,oBAAoBmC,MAAMV,SAAS,EAAEtB,mBACrCH,oBAAoBmC,MAAMR,SAAS,EAAExB,oBACpCH,oBAAoBE,KAAK2B,SAAS,EAAE1B;IAE7C;IAEA,sBAAsB;IACtB,IAAIc,IAAAA,2BAAoB,EAACf,OAAO;QAC9B,OAAOA,KAAKW,QAAQ,CAACC,IAAI,CAAC,CAACC,QACzBf,oBAAoBe,OAAOZ;IAE/B;IAEA,IAAIe,IAAAA,uBAAgB,EAAChB,OAAO;QAC1B,OAAOF,oBAAoBE,KAAKa,KAAK,EAAEZ;IACzC;IAEA,oBAAoB;IACpB,IAAIO,IAAAA,yBAAkB,EAACR,OAAO;QAC5B,OAAOA,KAAKW,QAAQ,CAACC,IAAI,CAAC,CAACC,QACzBf,oBAAoBe,OAAOZ;IAE/B;IAEA,sBAAsB;IACtB,IAAI2B,IAAAA,2BAAoB,EAAC5B,SAAS6B,IAAAA,mBAAY,EAAC7B,KAAK8B,QAAQ,CAAC9B,IAAI,GAAG;QAClE,OAAOA,KAAK8B,QAAQ,CAAC9B,IAAI,CAAC+B,WAAW,CAACX,KAAK,CAAC,CAACpB;YAC3C,OAAOF,oBAAoBE,MAAMC;QACnC;IACF;IAEA,OAAO;AACT;AAEO,MAAMF,kBAAkB,CAC7BmC,qBACAjC,gBACAE;IAEA,MAAMH,OAAOmC,IAAAA,qBAAa,EAACD;IAE3B,MAAME,mBAAmB,IAAIC,IAAIpC;IACjC,MAAMqC,yBAAyB,IAAID,IAAIlC;IAEvC,0BAA0B;IAC1B,IACEN,uBAAuB;QACrBG,MAAMA;QACNC,gBAAgBmC;QAChBlC,YAAY;QACZC,sBAAsBmC;IACxB,IACA;QACA,OAAO;IACT;IAEA,MAAM,IAAIxB,MAAM;AAClB"}
|