dsl-to-sql 1.0.0-fabric-1p-development.1
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/.turbo/turbo-build.log +9 -0
- package/.turbo/turbo-check-types.log +4 -0
- package/.turbo/turbo-lint.log +126 -0
- package/README.md +45 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +236 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/constants.ts.html +826 -0
- package/coverage/src/database_types.ts.html +136 -0
- package/coverage/src/epm-query-builder/EpmQueryBuilder.ts.html +166 -0
- package/coverage/src/epm-query-builder/base/BaseAdvancedAggregations.ts.html +568 -0
- package/coverage/src/epm-query-builder/base/BaseAnalyticalFunctions.ts.html +694 -0
- package/coverage/src/epm-query-builder/base/BaseCTEGenerator.ts.html +1459 -0
- package/coverage/src/epm-query-builder/base/BaseCountQueryBuilder.ts.html +400 -0
- package/coverage/src/epm-query-builder/base/BaseMeasureBuilder.ts.html +295 -0
- package/coverage/src/epm-query-builder/base/BaseOrderBuilder.ts.html +670 -0
- package/coverage/src/epm-query-builder/base/BasePaginationBuilder.ts.html +364 -0
- package/coverage/src/epm-query-builder/base/BaseQueryBuilder.ts.html +238 -0
- package/coverage/src/epm-query-builder/base/BaseRollupBuilder.ts.html +532 -0
- package/coverage/src/epm-query-builder/base/BaseSqlBuilder.ts.html +601 -0
- package/coverage/src/epm-query-builder/base/BaseSuperFilterBuilder.ts.html +1966 -0
- package/coverage/src/epm-query-builder/base/BaseUtilities.ts.html +1798 -0
- package/coverage/src/epm-query-builder/base/ColumnRefUtils.ts.html +211 -0
- package/coverage/src/epm-query-builder/base/RelationshipResolver.ts.html +706 -0
- package/coverage/src/epm-query-builder/base/SharedFilterBuilder.ts.html +1717 -0
- package/coverage/src/epm-query-builder/base/index.html +326 -0
- package/coverage/src/epm-query-builder/constants/Aggregations.ts.html +133 -0
- package/coverage/src/epm-query-builder/constants/Database.ts.html +103 -0
- package/coverage/src/epm-query-builder/constants/Source.ts.html +106 -0
- package/coverage/src/epm-query-builder/constants/index.html +146 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbAdvancedAggregations.ts.html +286 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbJoinBuilder.ts.html +280 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbMeasureBuilder.ts.html +1924 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbOrderBuilder.ts.html +769 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbPaginationBuilder.ts.html +643 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbQueryBuilder.ts.html +2644 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbRollupBuilder.ts.html +478 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbSuperFilterBuilder.ts.html +1195 -0
- package/coverage/src/epm-query-builder/dialects/duckdb/index.html +221 -0
- package/coverage/src/epm-query-builder/errors/QueryBuilderErrors.ts.html +280 -0
- package/coverage/src/epm-query-builder/errors/index.html +116 -0
- package/coverage/src/epm-query-builder/index.html +116 -0
- package/coverage/src/epm-query-builder/interfaces/IDatabaseQueryBuilder.ts.html +100 -0
- package/coverage/src/epm-query-builder/interfaces/index.html +131 -0
- package/coverage/src/epm-query-builder/interfaces/index.ts.html +88 -0
- package/coverage/src/epm-query-builder/utils/format.ts.html +151 -0
- package/coverage/src/epm-query-builder/utils/index.html +146 -0
- package/coverage/src/epm-query-builder/utils/sql.ts.html +247 -0
- package/coverage/src/epm-query-builder/utils/validation.ts.html +124 -0
- package/coverage/src/epm-query-builder/validation/QueryOptionsValidator.ts.html +631 -0
- package/coverage/src/epm-query-builder/validation/SqlQueryValidator.ts.html +475 -0
- package/coverage/src/epm-query-builder/validation/index.html +131 -0
- package/coverage/src/filters/FilterConditionBuilder.ts.html +427 -0
- package/coverage/src/filters/filter-types.ts.html +484 -0
- package/coverage/src/filters/index.html +131 -0
- package/coverage/src/index.html +176 -0
- package/coverage/src/index.ts.html +103 -0
- package/coverage/src/js-lib/JsToSqlParser.ts.html +736 -0
- package/coverage/src/js-lib/ParseContext.ts.html +532 -0
- package/coverage/src/js-lib/db/azuresql/AzureSqlCallExpressionVisitor.ts.html +196 -0
- package/coverage/src/js-lib/db/azuresql/index.html +116 -0
- package/coverage/src/js-lib/db/base/ArrayExpressionVisitor.ts.html +133 -0
- package/coverage/src/js-lib/db/base/AssignmentExpressionVisitor.ts.html +187 -0
- package/coverage/src/js-lib/db/base/BinaryExpressionVisitor.ts.html +223 -0
- package/coverage/src/js-lib/db/base/CallExpressionVisitor.ts.html +5479 -0
- package/coverage/src/js-lib/db/base/IdentifierVisitor.ts.html +283 -0
- package/coverage/src/js-lib/db/base/LiteralVisitor.ts.html +199 -0
- package/coverage/src/js-lib/db/base/MemberExpressionVisitor.ts.html +193 -0
- package/coverage/src/js-lib/db/base/ProgramVisitor.ts.html +139 -0
- package/coverage/src/js-lib/db/base/UnaryExpressionVisitor.ts.html +181 -0
- package/coverage/src/js-lib/db/base/VisitorInterface.ts.html +103 -0
- package/coverage/src/js-lib/db/base/index.html +251 -0
- package/coverage/src/js-lib/db/bigquery/BigQueryCallExpressionVisitor.ts.html +1747 -0
- package/coverage/src/js-lib/db/bigquery/index.html +116 -0
- package/coverage/src/js-lib/db/commonTransforms.ts.html +2074 -0
- package/coverage/src/js-lib/db/databricks/DatabricksCallExpressionVisitor.ts.html +1303 -0
- package/coverage/src/js-lib/db/databricks/index.html +116 -0
- package/coverage/src/js-lib/db/fabricsql/FabricSqlCallExpressionVisitor.ts.html +196 -0
- package/coverage/src/js-lib/db/fabricsql/index.html +116 -0
- package/coverage/src/js-lib/db/fabricwarehouse/FabricWarehouseCallExpressionVisitor.ts.html +292 -0
- package/coverage/src/js-lib/db/fabricwarehouse/index.html +116 -0
- package/coverage/src/js-lib/db/index.html +116 -0
- package/coverage/src/js-lib/db/postgresql/PostgreSqlCallExpressionVisitor.ts.html +985 -0
- package/coverage/src/js-lib/db/postgresql/index.html +116 -0
- package/coverage/src/js-lib/db/redshift/RedshiftCallExpressionVisitor.ts.html +685 -0
- package/coverage/src/js-lib/db/redshift/index.html +116 -0
- package/coverage/src/js-lib/db/sample/SampleCallExpressionVisitor.ts.html +196 -0
- package/coverage/src/js-lib/db/sample/index.html +116 -0
- package/coverage/src/js-lib/db/snowflake/SnowflakeCallExpressionVisitor.ts.html +1447 -0
- package/coverage/src/js-lib/db/snowflake/index.html +116 -0
- package/coverage/src/js-lib/db/validator/FormulaValidator.ts.html +4162 -0
- package/coverage/src/js-lib/db/validator/index.html +116 -0
- package/coverage/src/js-lib/index.html +131 -0
- package/coverage/src/js-lib/objects/BaseObject.ts.html +169 -0
- package/coverage/src/js-lib/objects/DateObject.ts.html +169 -0
- package/coverage/src/js-lib/objects/PctObject.ts.html +178 -0
- package/coverage/src/js-lib/objects/index.html +146 -0
- package/coverage/src/query-builder/PaginationBuilder.ts.html +142 -0
- package/coverage/src/query-builder/QueryBuilder.ts.html +3118 -0
- package/coverage/src/query-builder/SuperFilterBuilder.ts.html +1969 -0
- package/coverage/src/query-builder/index.html +146 -0
- package/coverage/src/runtime_var.ts.html +109 -0
- package/coverage/src/sql-lib/binary_expr.ts.html +133 -0
- package/coverage/src/sql-lib/case.ts.html +133 -0
- package/coverage/src/sql-lib/column.ts.html +139 -0
- package/coverage/src/sql-lib/else.ts.html +124 -0
- package/coverage/src/sql-lib/function.ts.html +112 -0
- package/coverage/src/sql-lib/index.html +251 -0
- package/coverage/src/sql-lib/join.ts.html +127 -0
- package/coverage/src/sql-lib/literal.ts.html +130 -0
- package/coverage/src/sql-lib/select.ts.html +547 -0
- package/coverage/src/sql-lib/unary_expr.ts.html +112 -0
- package/coverage/src/sql-lib/when.ts.html +130 -0
- package/coverage/src/sql_query_gen.ts.html +535 -0
- package/coverage/src/superFilter/DateFilterFactory.ts.html +625 -0
- package/coverage/src/superFilter/dateFunction.ts.html +193 -0
- package/coverage/src/superFilter/index.html +131 -0
- package/coverage/src/utils.ts.html +571 -0
- package/dist/index.cjs +8440 -0
- package/dist/index.d.cts +927 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +927 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8387 -0
- package/dist/index.js.map +1 -0
- package/eslint.config.js +4 -0
- package/jest.config.ts +44 -0
- package/package.json +45 -0
- package/src/constants.ts +247 -0
- package/src/epm-query-builder/EpmQueryBuilder.ts +27 -0
- package/src/epm-query-builder/base/BaseAdvancedAggregations.ts +161 -0
- package/src/epm-query-builder/base/BaseAnalyticalFunctions.ts +203 -0
- package/src/epm-query-builder/base/BaseCTEGenerator.ts +458 -0
- package/src/epm-query-builder/base/BaseCountQueryBuilder.ts +105 -0
- package/src/epm-query-builder/base/BaseMeasureBuilder.ts +87 -0
- package/src/epm-query-builder/base/BaseOrderBuilder.ts +195 -0
- package/src/epm-query-builder/base/BasePaginationBuilder.ts +93 -0
- package/src/epm-query-builder/base/BaseQueryBuilder.ts +51 -0
- package/src/epm-query-builder/base/BaseRollupBuilder.ts +149 -0
- package/src/epm-query-builder/base/BaseSqlBuilder.ts +172 -0
- package/src/epm-query-builder/base/BaseSuperFilterBuilder.ts +627 -0
- package/src/epm-query-builder/base/BaseUtilities.ts +571 -0
- package/src/epm-query-builder/base/ColumnRefUtils.ts +42 -0
- package/src/epm-query-builder/base/RelationshipResolver.ts +207 -0
- package/src/epm-query-builder/base/SharedFilterBuilder.ts +544 -0
- package/src/epm-query-builder/constants/Aggregations.ts +16 -0
- package/src/epm-query-builder/constants/Database.ts +6 -0
- package/src/epm-query-builder/constants/Source.ts +7 -0
- package/src/epm-query-builder/dialects/duckdb/DuckDbAdvancedAggregations.ts +67 -0
- package/src/epm-query-builder/dialects/duckdb/DuckDbJoinBuilder.ts +65 -0
- package/src/epm-query-builder/dialects/duckdb/DuckDbMeasureBuilder.ts +626 -0
- package/src/epm-query-builder/dialects/duckdb/DuckDbOrderBuilder.ts +228 -0
- package/src/epm-query-builder/dialects/duckdb/DuckDbPaginationBuilder.ts +186 -0
- package/src/epm-query-builder/dialects/duckdb/DuckDbQueryBuilder.ts +853 -0
- package/src/epm-query-builder/dialects/duckdb/DuckDbRollupBuilder.ts +131 -0
- package/src/epm-query-builder/dialects/duckdb/DuckDbSuperFilterBuilder.ts +370 -0
- package/src/epm-query-builder/errors/QueryBuilderErrors.ts +65 -0
- package/src/epm-query-builder/interfaces/IDatabaseQueryBuilder.ts +5 -0
- package/src/epm-query-builder/interfaces/index.ts +1 -0
- package/src/epm-query-builder/types/query-builder-types.d.ts +289 -0
- package/src/epm-query-builder/utils/format.ts +22 -0
- package/src/epm-query-builder/utils/sql.ts +54 -0
- package/src/epm-query-builder/utils/validation.ts +13 -0
- package/src/epm-query-builder/validation/QueryOptionsValidator.ts +182 -0
- package/src/epm-query-builder/validation/SqlQueryValidator.ts +130 -0
- package/src/filters/FilterConditionBuilder.ts +114 -0
- package/src/filters/filter-types.ts +133 -0
- package/src/index.ts +10 -0
- package/src/js-lib/JsToSqlParser.ts +217 -0
- package/src/js-lib/ParseContext.ts +149 -0
- package/src/js-lib/db/base/ArrayExpressionVisitor.ts +16 -0
- package/src/js-lib/db/base/AssignmentExpressionVisitor.ts +34 -0
- package/src/js-lib/db/base/BinaryExpressionVisitor.ts +46 -0
- package/src/js-lib/db/base/CallExpressionVisitor.ts +1798 -0
- package/src/js-lib/db/base/IdentifierVisitor.ts +66 -0
- package/src/js-lib/db/base/LiteralVisitor.ts +38 -0
- package/src/js-lib/db/base/MemberExpressionVisitor.ts +36 -0
- package/src/js-lib/db/base/ProgramVisitor.ts +18 -0
- package/src/js-lib/db/base/UnaryExpressionVisitor.ts +32 -0
- package/src/js-lib/db/base/VisitorInterface.ts +6 -0
- package/src/js-lib/db/validator/FormulaValidator.ts +1235 -0
- package/src/js-lib/objects/BaseObject.ts +28 -0
- package/src/js-lib/objects/DateObject.ts +28 -0
- package/src/js-lib/objects/PctObject.ts +31 -0
- package/src/query-builder/PaginationBuilder.ts +19 -0
- package/src/query-builder/QueryBuilder.ts +1035 -0
- package/src/query-builder/SuperFilterBuilder.ts +628 -0
- package/src/runtime_var.ts +8 -0
- package/src/sql-lib/binary_expr.ts +16 -0
- package/src/sql-lib/case.ts +16 -0
- package/src/sql-lib/column.ts +18 -0
- package/src/sql-lib/else.ts +13 -0
- package/src/sql-lib/function.ts +9 -0
- package/src/sql-lib/join.ts +14 -0
- package/src/sql-lib/literal.ts +15 -0
- package/src/sql-lib/select.ts +154 -0
- package/src/sql-lib/unary_expr.ts +9 -0
- package/src/sql-lib/when.ts +15 -0
- package/src/sql-types.d.ts +565 -0
- package/src/sql_query_gen.ts +150 -0
- package/src/superFilter/DateFilterFactory.ts +180 -0
- package/src/superFilter/dateFunction.ts +36 -0
- package/src/utils.ts +354 -0
- package/test-output/report/junit.xml +329 -0
- package/tests/JsToSqlParser.test.ts +163 -0
- package/tests/QueryBuilder.test.ts +1320 -0
- package/tests/js-lib/CallExpressionVisitor.test.ts +820 -0
- package/tests/mocks/MockQueryResolver.ts +14 -0
- package/tests/sanity.test.ts +146 -0
- package/tests/sql-lib/binary_expr.test.ts +75 -0
- package/tests/sql-lib/case.test.ts +117 -0
- package/tests/sql-lib/column.test.ts +87 -0
- package/tests/sql-lib/else.test.ts +56 -0
- package/tests/sql-lib/function.test.ts +96 -0
- package/tests/sql-lib/literal.test.ts +75 -0
- package/tests/sql-lib/select.test.ts +245 -0
- package/tests/sql-lib/unary_expr.test.ts +32 -0
- package/tests/utils.test.ts +13 -0
- package/tsconfig.json +24 -0
- package/tsdown.config.ts +23 -0
|
@@ -0,0 +1,1235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validators.ts
|
|
3
|
+
*
|
|
4
|
+
* This file contains reusable validation functions for transform argument checking.
|
|
5
|
+
* Each validator accepts the parsing context and arguments to validate types, argument count, etc.
|
|
6
|
+
*
|
|
7
|
+
* These functions help keep transform functions clean by centralizing validation logic,
|
|
8
|
+
* providing consistent error handling and context updates.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* import { concatenateTransformValidator, dateArgumentValidator } from './validators';
|
|
12
|
+
*
|
|
13
|
+
* // In your transform function:
|
|
14
|
+
* concatenateTransformValidator(context, args);
|
|
15
|
+
* dateArgumentValidator(context, dateArg, 'MONTH');
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { ParseContext } from '../../ParseContext';
|
|
19
|
+
import { ExpressionValue } from '../../../sql-types';
|
|
20
|
+
import { getArgType } from '@/utils';
|
|
21
|
+
|
|
22
|
+
export function ifTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
23
|
+
if (args.length < 3) {
|
|
24
|
+
context.isValid = false;
|
|
25
|
+
context.error = 'IF() requires 3 arguments';
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const trueValueType = getArgType(args[1], context);
|
|
29
|
+
const falseValueType = getArgType(args[2], context);
|
|
30
|
+
if (trueValueType !== falseValueType) {
|
|
31
|
+
context.isValid = false;
|
|
32
|
+
context.error = `Both true value and false value should of same type`;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (falseValueType) context.returnType = falseValueType;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function todayTransformValidator(context: ParseContext): void {
|
|
39
|
+
context.returnType = 'date';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function nowTransformValidator(context: ParseContext): void {
|
|
43
|
+
context.returnType = 'datetime';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function concatenateTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
47
|
+
if (args.length < 2) {
|
|
48
|
+
context.isValid = false;
|
|
49
|
+
context.error = 'CONCATENATE() requires at least 2 arguments';
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
context.returnType = 'string';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function lowerTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
56
|
+
if (!arg) {
|
|
57
|
+
context.isValid = false;
|
|
58
|
+
context.error = 'LOWER() requires 1 argument';
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (getArgType(arg, context) !== 'string') {
|
|
62
|
+
context.isValid = false;
|
|
63
|
+
context.error = 'Argument to LOWER must be of type string';
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
context.returnType = 'string';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function dateArgumentValidator(context: ParseContext, arg: ExpressionValue, fnName: string) {
|
|
70
|
+
if (!arg) {
|
|
71
|
+
context.isValid = false;
|
|
72
|
+
context.error = `${fnName}() requires 1 argument`;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (getArgType(arg, context) !== 'date') {
|
|
76
|
+
context.isValid = false;
|
|
77
|
+
context.error = `Argument to ${fnName} must be of type date in format 'YYYY-MM-DD'`;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
context.returnType = 'number';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function trimTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
84
|
+
if (!arg) {
|
|
85
|
+
context.isValid = false;
|
|
86
|
+
context.error = 'TRIM() requires 1 argument';
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (getArgType(arg, context) !== 'string') {
|
|
90
|
+
context.isValid = false;
|
|
91
|
+
context.error = 'Argument to TRIM must be of type string';
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
context.returnType = 'string';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function upperTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
98
|
+
if (!arg) {
|
|
99
|
+
context.isValid = false;
|
|
100
|
+
context.error = 'UPPER() requires 1 argument';
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (getArgType(arg, context) !== 'string') {
|
|
104
|
+
context.isValid = false;
|
|
105
|
+
context.error = 'Argument to UPPER must be of type string';
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
context.returnType = 'string';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function lenTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
112
|
+
if (!arg) {
|
|
113
|
+
context.isValid = false;
|
|
114
|
+
context.error = 'LEN() requires exactly 1 argument';
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (getArgType(arg, context) !== 'string') {
|
|
118
|
+
context.isValid = false;
|
|
119
|
+
context.error = 'Argument to LEN must be of type string';
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
context.returnType = 'number';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function leftTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
126
|
+
if (args.length !== 2) {
|
|
127
|
+
context.isValid = false;
|
|
128
|
+
context.error = 'LEFT() requires exactly 2 arguments';
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (getArgType(args[0], context) !== 'string') {
|
|
132
|
+
context.isValid = false;
|
|
133
|
+
context.error = 'First argument to LEFT must be of type string';
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (getArgType(args[1], context) !== 'number') {
|
|
137
|
+
context.isValid = false;
|
|
138
|
+
context.error = 'Second argument to LEFT must be of type number';
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
context.returnType = 'string';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function rightTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
145
|
+
if (args.length !== 2) {
|
|
146
|
+
context.isValid = false;
|
|
147
|
+
context.error = 'RIGHT() requires exactly 2 arguments';
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (getArgType(args[0], context) !== 'string') {
|
|
151
|
+
context.isValid = false;
|
|
152
|
+
context.error = 'First argument to RIGHT must be of type string';
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (getArgType(args[1], context) !== 'number') {
|
|
156
|
+
context.isValid = false;
|
|
157
|
+
context.error = 'Second argument to RIGHT must be of type number';
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
context.returnType = 'string';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function replaceTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
164
|
+
const types = ['string', 'number', 'number', 'string'];
|
|
165
|
+
if (args.length !== types.length) {
|
|
166
|
+
context.isValid = false;
|
|
167
|
+
context.error = 'REPLACE() requires 4 arguments';
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
args.forEach((arg, i) => {
|
|
171
|
+
if (getArgType(arg, context) !== types[i]) {
|
|
172
|
+
context.isValid = false;
|
|
173
|
+
context.error = `Argument ${i + 1} to REPLACE must be of type ${types[i]}`;
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
context.returnType = 'string';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function reptTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
181
|
+
const types = ['string', 'number'];
|
|
182
|
+
if (args.length !== types.length) {
|
|
183
|
+
context.isValid = false;
|
|
184
|
+
context.error = 'REPT() requires 2 arguments';
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
args.forEach((arg, i) => {
|
|
188
|
+
if (getArgType(arg, context) !== types[i]) {
|
|
189
|
+
context.isValid = false;
|
|
190
|
+
context.error = `Argument ${i + 1} to REPT must be of type ${types[i]}`;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
context.returnType = 'string';
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function matchTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
198
|
+
const types = ['string', 'string'];
|
|
199
|
+
if (args.length !== types.length) {
|
|
200
|
+
context.isValid = false;
|
|
201
|
+
context.error = 'MATCH() requires 2 arguments';
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
args.forEach((arg, i) => {
|
|
205
|
+
if (getArgType(arg, context) !== types[i]) {
|
|
206
|
+
context.isValid = false;
|
|
207
|
+
context.error = `Argument ${i + 1} to MATCH must be of type ${types[i]}`;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
context.returnType = 'boolean';
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function dateAddTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
215
|
+
if (args.length !== 2) {
|
|
216
|
+
context.isValid = false;
|
|
217
|
+
context.error = 'DATEADD() requires 2 arguments';
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (getArgType(args[0], context) !== 'date') {
|
|
221
|
+
context.isValid = false;
|
|
222
|
+
context.error = "First argument to DATEADD must be of type date in format 'YYYY-MM-DD'";
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (getArgType(args[1], context) !== 'number') {
|
|
226
|
+
context.isValid = false;
|
|
227
|
+
context.error = 'Second argument to DATEADD must be of type number';
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
context.returnType = 'date';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function dateDiffTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
234
|
+
if (args.length !== 2) {
|
|
235
|
+
context.isValid = false;
|
|
236
|
+
context.error = 'DATEDIFF() requires 2 arguments';
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const types = ['date', 'date'];
|
|
240
|
+
args.forEach((arg, i) => {
|
|
241
|
+
if (getArgType(arg, context) !== types[i]) {
|
|
242
|
+
context.isValid = false;
|
|
243
|
+
context.error = `Argument ${i + 1} to DATEDIFF must be of type ${types[i]} in format 'YYYY-MM-DD'`;
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
context.returnType = 'number';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function dayTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
251
|
+
if (!arg) {
|
|
252
|
+
context.isValid = false;
|
|
253
|
+
context.error = 'DAY() requires 1 argument';
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (getArgType(arg, context) !== 'date') {
|
|
257
|
+
context.isValid = false;
|
|
258
|
+
context.error = "Argument to DAY must be of type date in format 'YYYY-MM-DD'";
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
context.returnType = 'number';
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function monthTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
265
|
+
if (!arg) {
|
|
266
|
+
context.isValid = false;
|
|
267
|
+
context.error = 'MONTH() requires 1 argument';
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (getArgType(arg, context) !== 'date') {
|
|
271
|
+
context.isValid = false;
|
|
272
|
+
context.error = "Argument to MONTH must be of type date in format 'YYYY-MM-DD'";
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
context.returnType = 'number';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export function yearTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
279
|
+
if (!arg) {
|
|
280
|
+
context.isValid = false;
|
|
281
|
+
context.error = 'YEAR() requires 1 argument';
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (getArgType(arg, context) !== 'date') {
|
|
285
|
+
context.isValid = false;
|
|
286
|
+
context.error = "Argument to YEAR must be of type date in format 'YYYY-MM-DD'";
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
context.returnType = 'number';
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export function eomonthTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
293
|
+
if (args.length < 1 || args.length > 2) {
|
|
294
|
+
context.isValid = false;
|
|
295
|
+
context.error = 'EOMONTH() requires 1 or 2 arguments';
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (getArgType(args[0], context) !== 'date') {
|
|
300
|
+
context.isValid = false;
|
|
301
|
+
context.error = "First argument to EOMONTH must be of type date in format 'YYYY-MM-DD'";
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (args.length === 2 && getArgType(args[1], context) !== 'number') {
|
|
306
|
+
context.isValid = false;
|
|
307
|
+
context.error = 'Second argument to EOMONTH must be of type number';
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
context.returnType = 'date';
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export function divideTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
315
|
+
if (args.length !== 2) {
|
|
316
|
+
context.isValid = false;
|
|
317
|
+
context.error = 'DIVIDE() requires 2 arguments';
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const types = ['number', 'number'];
|
|
322
|
+
args.forEach((arg, i) => {
|
|
323
|
+
if (getArgType(arg, context) !== types[i]) {
|
|
324
|
+
context.isValid = false;
|
|
325
|
+
context.error = `Argument ${i + 1} to DIVIDE must be of type ${types[i]}`;
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
context.returnType = 'number';
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function andTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
334
|
+
if (args.length < 2) {
|
|
335
|
+
context.isValid = false;
|
|
336
|
+
context.error = 'AND() requires at least 2 arguments';
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
args.forEach((arg, i) => {
|
|
341
|
+
if (getArgType(arg, context) !== 'boolean') {
|
|
342
|
+
context.isValid = false;
|
|
343
|
+
context.error = `Argument ${i + 1} to AND must be of type boolean`;
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
context.returnType = 'boolean';
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function orTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
352
|
+
if (args.length < 2) {
|
|
353
|
+
context.isValid = false;
|
|
354
|
+
context.error = 'OR() requires at least 2 arguments';
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
args.forEach((arg, i) => {
|
|
359
|
+
if (getArgType(arg, context) !== 'boolean') {
|
|
360
|
+
context.isValid = false;
|
|
361
|
+
context.error = `Argument ${i + 1} to OR must be of type boolean`;
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
context.returnType = 'boolean';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export function ceilTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
370
|
+
if (!arg) {
|
|
371
|
+
context.isValid = false;
|
|
372
|
+
context.error = 'CEIL() requires 1 argument';
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (getArgType(arg, context) !== 'number') {
|
|
377
|
+
context.isValid = false;
|
|
378
|
+
context.error = 'Argument to CEIL must be of type number';
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
context.returnType = 'number';
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export function floorTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
386
|
+
if (!arg) {
|
|
387
|
+
context.isValid = false;
|
|
388
|
+
context.error = 'FLOOR() requires 1 argument';
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (getArgType(arg, context) !== 'number') {
|
|
393
|
+
context.isValid = false;
|
|
394
|
+
context.error = 'Argument to FLOOR must be of type number';
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
context.returnType = 'number';
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export function absTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
402
|
+
if (!arg) {
|
|
403
|
+
context.isValid = false;
|
|
404
|
+
context.error = 'ABS() requires 1 argument';
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (getArgType(arg, context) !== 'number') {
|
|
409
|
+
context.isValid = false;
|
|
410
|
+
context.error = 'Argument to ABS must be of type number';
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
context.returnType = 'number';
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export function roundTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
418
|
+
if (args.length < 1 || args.length > 2) {
|
|
419
|
+
context.isValid = false;
|
|
420
|
+
context.error = 'ROUND() requires 1 or 2 arguments';
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const valueType = getArgType(args[0], context);
|
|
425
|
+
if (valueType !== 'number') {
|
|
426
|
+
context.isValid = false;
|
|
427
|
+
context.error = 'First argument to ROUND must be of type number';
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (args[1]) {
|
|
432
|
+
const decimalType = getArgType(args[1], context);
|
|
433
|
+
if (decimalType !== 'number') {
|
|
434
|
+
context.isValid = false;
|
|
435
|
+
context.error = 'Second argument to ROUND must be of type number';
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
context.returnType = 'number';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export function expTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
444
|
+
if (!arg) {
|
|
445
|
+
context.isValid = false;
|
|
446
|
+
context.error = 'EXP() requires exactly 1 argument';
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const type = getArgType(arg, context);
|
|
450
|
+
if (type !== 'number') {
|
|
451
|
+
context.isValid = false;
|
|
452
|
+
context.error = 'Argument to EXP must be of type number';
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
context.returnType = 'number';
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export function powTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
459
|
+
if (args.length !== 2) {
|
|
460
|
+
context.isValid = false;
|
|
461
|
+
context.error = 'POW() requires exactly 2 arguments';
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const types = ['number', 'number'];
|
|
465
|
+
args.forEach((arg, i) => {
|
|
466
|
+
if (getArgType(arg, context) !== types[i]) {
|
|
467
|
+
context.isValid = false;
|
|
468
|
+
context.error = `Argument ${i + 1} to POW must be of type ${types[i]}`;
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
context.returnType = 'number';
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export function logTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
476
|
+
if (args.length < 1 || args.length > 2) {
|
|
477
|
+
context.isValid = false;
|
|
478
|
+
context.error = 'LOG() requires 1 or 2 arguments';
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
args.forEach((arg, i) => {
|
|
482
|
+
if (getArgType(arg, context) !== 'number') {
|
|
483
|
+
context.isValid = false;
|
|
484
|
+
context.error = `Argument ${i + 1} to LOG must be of type number`;
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
context.returnType = 'number';
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export function sqrtTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
492
|
+
if (!arg) {
|
|
493
|
+
context.isValid = false;
|
|
494
|
+
context.error = 'SQRT() requires exactly 1 arguments';
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (getArgType(arg, context) !== 'number') {
|
|
498
|
+
context.isValid = false;
|
|
499
|
+
context.error = 'Argument to SQRT must be of type number';
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
context.returnType = 'number';
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export function modTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
506
|
+
if (args.length !== 2) {
|
|
507
|
+
context.isValid = false;
|
|
508
|
+
context.error = 'MOD() requires exactly 2 arguments';
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const types = ['number', 'number'];
|
|
512
|
+
args.forEach((arg, i) => {
|
|
513
|
+
if (getArgType(arg, context) !== types[i]) {
|
|
514
|
+
context.isValid = false;
|
|
515
|
+
context.error = `Argument ${i + 1} to MOD must be of type ${types[i]}`;
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
context.returnType = 'number';
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export function notTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
523
|
+
if (!arg) {
|
|
524
|
+
context.isValid = false;
|
|
525
|
+
context.error = 'NOT() requires exactly 1 argument';
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (getArgType(arg, context) !== 'boolean') {
|
|
529
|
+
context.isValid = false;
|
|
530
|
+
context.error = 'Argument to NOT must be of type boolean';
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
context.returnType = 'boolean';
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export function randTransformValidator(context: ParseContext) {
|
|
537
|
+
context.returnType = 'number';
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export function randBetweenTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
541
|
+
if (args.length !== 2) {
|
|
542
|
+
context.isValid = false;
|
|
543
|
+
context.error = 'RAND_BETWEEN() requires exactly 2 arguments';
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
const types = ['number', 'number'];
|
|
547
|
+
args.forEach((arg, i) => {
|
|
548
|
+
if (getArgType(arg, context) !== types[i]) {
|
|
549
|
+
context.isValid = false;
|
|
550
|
+
context.error = `Argument ${i + 1} to RAND_BETWEEN must be of type ${types[i]}`;
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
context.returnType = 'number';
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
export function averageTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
558
|
+
if (args.length < 1) {
|
|
559
|
+
context.isValid = false;
|
|
560
|
+
context.error = 'AVERAGE() requires at least 1 argument';
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
for (let i = 0; i < args.length; i++) {
|
|
564
|
+
if (getArgType(args[i], context) !== 'number') {
|
|
565
|
+
context.isValid = false;
|
|
566
|
+
context.error = `Argument ${i + 1} to AVERAGE must be of type number`;
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
context.returnType = 'number';
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
export function averageIfTransformValidator(
|
|
574
|
+
context: ParseContext,
|
|
575
|
+
valueList: ExpressionValue[],
|
|
576
|
+
condition: ExpressionValue,
|
|
577
|
+
) {
|
|
578
|
+
if (valueList.length < 1) {
|
|
579
|
+
context.isValid = false;
|
|
580
|
+
context.error = 'AVERAGE_IF() requires at least one value to average';
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
for (let i = 0; i < valueList.length; i++) {
|
|
585
|
+
if (getArgType(valueList[i], context) !== 'number') {
|
|
586
|
+
context.isValid = false;
|
|
587
|
+
context.error = `Argument ${i + 1} in value list must be of type number`;
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (condition.type !== 'string') {
|
|
593
|
+
context.isValid = false;
|
|
594
|
+
context.error =
|
|
595
|
+
'The first argument in AVERAGE_IF must be a string representing a condition expression';
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
context.returnType = 'number';
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export function averageXNegTransformValidator(context: ParseContext, valueList: ExpressionValue[]) {
|
|
603
|
+
if (valueList.length < 1) {
|
|
604
|
+
context.isValid = false;
|
|
605
|
+
context.error = 'AVERAGE_X_NEG() requires at least one numeric argument';
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
for (let i = 0; i < valueList.length; i++) {
|
|
609
|
+
if (getArgType(valueList[i], context) !== 'number') {
|
|
610
|
+
context.isValid = false;
|
|
611
|
+
context.error = `Argument ${i + 1} to AVERAGE_X_NEG must be of type number`;
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
context.returnType = 'number';
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
export function averageXZeroTransformValidator(
|
|
619
|
+
context: ParseContext,
|
|
620
|
+
valueList: ExpressionValue[],
|
|
621
|
+
) {
|
|
622
|
+
if (valueList.length < 1) {
|
|
623
|
+
context.isValid = false;
|
|
624
|
+
context.error = 'AVERAGE_X_ZERO() requires at least one numeric argument';
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
for (let i = 0; i < valueList.length; i++) {
|
|
628
|
+
if (getArgType(valueList[i], context) !== 'number') {
|
|
629
|
+
context.isValid = false;
|
|
630
|
+
context.error = `Argument ${i + 1} to AVERAGE_X_ZERO must be of type number`;
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
context.returnType = 'number';
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export function averageXZeroNegTransformValidator(
|
|
638
|
+
context: ParseContext,
|
|
639
|
+
valueList: ExpressionValue[],
|
|
640
|
+
) {
|
|
641
|
+
if (valueList.length < 1) {
|
|
642
|
+
context.isValid = false;
|
|
643
|
+
context.error = 'AVERAGE_X_ZERO_NEG() requires at least one numeric argument';
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
for (let i = 0; i < valueList.length; i++) {
|
|
647
|
+
if (getArgType(valueList[i], context) !== 'number') {
|
|
648
|
+
context.isValid = false;
|
|
649
|
+
context.error = `Argument ${i + 1} to AVERAGE_X_ZERO_NEG must be of type number`;
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
context.returnType = 'number';
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
export function numberValueTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
657
|
+
if (args.length < 1 || args.length > 3) {
|
|
658
|
+
context.isValid = false;
|
|
659
|
+
context.error = 'NUMBERVALUE() requires 1, 2, or 3 arguments';
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
if (getArgType(args[0], context) !== 'string' && getArgType(args[0], context) !== 'number') {
|
|
663
|
+
context.isValid = false;
|
|
664
|
+
context.error = 'First argument to NUMBERVALUE must be string or number';
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
if (args[1] && getArgType(args[1], context) !== 'string') {
|
|
668
|
+
context.isValid = false;
|
|
669
|
+
context.error = 'Second argument to NUMBERVALUE must be string';
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
if (args[2] && getArgType(args[2], context) !== 'string') {
|
|
673
|
+
context.isValid = false;
|
|
674
|
+
context.error = 'Third argument to NUMBERVALUE must be string';
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
context.returnType = 'number';
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
export function oddTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
681
|
+
if (!arg) {
|
|
682
|
+
context.isValid = false;
|
|
683
|
+
context.error = 'ODD() requires 1 argument';
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
if (getArgType(arg, context) !== 'number') {
|
|
687
|
+
context.isValid = false;
|
|
688
|
+
context.error = 'Argument to ODD must be of type number';
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
context.returnType = 'number';
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export function evenTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
695
|
+
if (!arg) {
|
|
696
|
+
context.isValid = false;
|
|
697
|
+
context.error = 'EVEN() requires 1 argument';
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
if (getArgType(arg, context) !== 'number') {
|
|
701
|
+
context.isValid = false;
|
|
702
|
+
context.error = 'Argument to EVEN must be of type number';
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
context.returnType = 'number';
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
export function inTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
709
|
+
if (args.length !== 2) {
|
|
710
|
+
context.isValid = false;
|
|
711
|
+
context.error = 'IN() requires exactly 2 arguments: column and an array of values';
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
const [column, values] = args;
|
|
715
|
+
const columnType = getArgType(column, context);
|
|
716
|
+
if (columnType === null || !['string', 'number'].includes(columnType)) {
|
|
717
|
+
context.isValid = false;
|
|
718
|
+
context.error =
|
|
719
|
+
'First argument to IN must be a string or number or column reference of type string or number';
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
if (values.type !== 'expr_list' || !Array.isArray(values.value)) {
|
|
723
|
+
context.isValid = false;
|
|
724
|
+
context.error = 'Second argument to IN must be an array of values';
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
context.returnType = 'boolean';
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
export function sumTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
731
|
+
if (args.length < 1) {
|
|
732
|
+
context.isValid = false;
|
|
733
|
+
context.error = 'SUM() requires 1 or more arguments';
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
for (let i = 0; i < args.length; i++) {
|
|
737
|
+
const argType = getArgType(args[i], context);
|
|
738
|
+
if (argType !== 'number') {
|
|
739
|
+
context.isValid = false;
|
|
740
|
+
context.error = `Argument ${i + 1} to SUM must be of type number`;
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
context.returnType = 'number';
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
export function indexOfTransformValidator(
|
|
748
|
+
context: ParseContext,
|
|
749
|
+
valueList: ExpressionValue[],
|
|
750
|
+
valueToFind: ExpressionValue,
|
|
751
|
+
) {
|
|
752
|
+
if (!valueList || !valueToFind) {
|
|
753
|
+
context.isValid = false;
|
|
754
|
+
context.error = 'INDEXOF() requires 2 arguments';
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
if (!Array.isArray(valueList) || valueList.length === 0) {
|
|
758
|
+
context.isValid = false;
|
|
759
|
+
context.error = 'First argument to INDEXOF must be a non-empty array';
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
for (let i = 0; i < valueList.length; i++) {
|
|
763
|
+
const t = getArgType(valueList[i], context);
|
|
764
|
+
if (t !== 'string' && t !== 'number') {
|
|
765
|
+
context.isValid = false;
|
|
766
|
+
context.error = `Argument ${i + 1} in valueList must be string or number`;
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
const searchType = getArgType(valueToFind, context);
|
|
771
|
+
if (searchType !== 'string' && searchType !== 'number') {
|
|
772
|
+
context.isValid = false;
|
|
773
|
+
context.error = 'Second argument to INDEXOF must be string or number';
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
context.returnType = 'number';
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
export function isEmptyTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
780
|
+
if (!arg) {
|
|
781
|
+
context.isValid = false;
|
|
782
|
+
context.error = 'ISEMPTY() requires exactly 1 argument';
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const type = getArgType(arg, context);
|
|
786
|
+
if (!['string', 'null'].includes(type || '')) {
|
|
787
|
+
context.isValid = false;
|
|
788
|
+
context.error = 'Argument to ISEMPTY must be of type string or null';
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
context.returnType = 'boolean';
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
export function isNumberTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
795
|
+
if (!arg) {
|
|
796
|
+
context.isValid = false;
|
|
797
|
+
context.error = 'ISNUMBER() requires exactly 1 argument';
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const type = getArgType(arg, context);
|
|
801
|
+
if (type !== 'string' && type !== 'number') {
|
|
802
|
+
context.isValid = false;
|
|
803
|
+
context.error = 'Argument to ISNUMBER must be of type string or number';
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
context.returnType = 'boolean';
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
export function maxAggregateTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
810
|
+
if (args.length < 1) {
|
|
811
|
+
context.isValid = false;
|
|
812
|
+
context.error = 'GREATEST() requires 1 or more arguments';
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
for (let i = 0; i < args.length; i++) {
|
|
816
|
+
const type = getArgType(args[i], context);
|
|
817
|
+
if (type !== 'number') {
|
|
818
|
+
context.isValid = false;
|
|
819
|
+
context.error = `Argument ${i + 1} to GREATEST must be of type number`;
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
context.returnType = 'number';
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
export function minAggregateTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
827
|
+
if (args.length < 1) {
|
|
828
|
+
context.isValid = false;
|
|
829
|
+
context.error = 'LEAST() requires 1 or more arguments';
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
for (let i = 0; i < args.length; i++) {
|
|
833
|
+
const type = getArgType(args[i], context);
|
|
834
|
+
if (type !== 'number') {
|
|
835
|
+
context.isValid = false;
|
|
836
|
+
context.error = `Argument ${i + 1} to LEAST must be of type number`;
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
context.returnType = 'number';
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
export function midTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
844
|
+
if (args.length !== 3) {
|
|
845
|
+
context.isValid = false;
|
|
846
|
+
context.error = 'MID() requires exactly 3 arguments';
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
const [strArg, startArg, lengthArg] = args;
|
|
850
|
+
if (getArgType(strArg, context) !== 'string') {
|
|
851
|
+
context.isValid = false;
|
|
852
|
+
context.error = 'First argument to MID must be of type string';
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (getArgType(startArg, context) !== 'number') {
|
|
856
|
+
context.isValid = false;
|
|
857
|
+
context.error = 'Second argument to MID must be of type number';
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
if (getArgType(lengthArg, context) !== 'number') {
|
|
861
|
+
context.isValid = false;
|
|
862
|
+
context.error = 'Third argument to MID must be of type number';
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
context.returnType = 'string';
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
export function medianTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
869
|
+
if (args.length < 1) {
|
|
870
|
+
context.isValid = false;
|
|
871
|
+
context.error = 'MEDIAN() requires 1 or more arguments';
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
for (let i = 0; i < args.length; i++) {
|
|
875
|
+
const type = getArgType(args[i], context);
|
|
876
|
+
if (type !== 'number') {
|
|
877
|
+
context.isValid = false;
|
|
878
|
+
context.error = `Argument ${i + 1} to MEDIAN must be of type number`;
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
context.returnType = 'number';
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
export function modeTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
886
|
+
if (args.length < 1) {
|
|
887
|
+
context.isValid = false;
|
|
888
|
+
context.error = 'MODE() requires 1 or more arguments';
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
for (let i = 0; i < args.length; i++) {
|
|
892
|
+
const type = getArgType(args[i], context);
|
|
893
|
+
if (type !== 'number') {
|
|
894
|
+
context.isValid = false;
|
|
895
|
+
context.error = `Argument ${i + 1} to MODE must be of type number`;
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
context.returnType = 'number';
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
export function valueTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
903
|
+
if (!arg) {
|
|
904
|
+
context.isValid = false;
|
|
905
|
+
context.error = 'VALUE() requires exactly 1 argument';
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const type = getArgType(arg, context);
|
|
910
|
+
if (!['string', 'number'].includes(type || '')) {
|
|
911
|
+
context.isValid = false;
|
|
912
|
+
context.error = 'VALUE() accepts only string or number as input';
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
context.returnType = 'number';
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
export function pctTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
920
|
+
if (!arg) {
|
|
921
|
+
context.isValid = false;
|
|
922
|
+
context.error = 'PCT() requires exactly 1 argument';
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
const type = getArgType(arg, context);
|
|
927
|
+
if (type !== 'number') {
|
|
928
|
+
context.isValid = false;
|
|
929
|
+
context.error = 'PCT() argument must be of type number';
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
context.returnType = 'number';
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
export function xorTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
937
|
+
if (args.length !== 2) {
|
|
938
|
+
context.isValid = false;
|
|
939
|
+
context.error = 'XOR() requires exactly 2 arguments';
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
const [arg1Type, arg2Type] = args.map((arg) => getArgType(arg, context));
|
|
944
|
+
if (arg1Type !== 'boolean' || arg2Type !== 'boolean') {
|
|
945
|
+
context.isValid = false;
|
|
946
|
+
context.error = 'XOR() arguments must both be of type boolean';
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
context.returnType = 'boolean';
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
export function textTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
954
|
+
if (args.length < 2 || args.length > 3) {
|
|
955
|
+
context.isValid = false;
|
|
956
|
+
context.error = 'TEXT() requires 2 or 3 arguments';
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
const [valueType, formatType, localeType] = args.map((arg) => getArgType(arg, context));
|
|
961
|
+
if (!['number', 'date'].includes(valueType || '')) {
|
|
962
|
+
context.isValid = false;
|
|
963
|
+
context.error = 'First argument to TEXT() must be of type number or date';
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
if (formatType !== 'string') {
|
|
967
|
+
context.isValid = false;
|
|
968
|
+
context.error = 'Second argument to TEXT() must be a string format pattern';
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
if (args[2] && localeType !== 'string') {
|
|
972
|
+
context.isValid = false;
|
|
973
|
+
context.error = 'Third argument to TEXT() (locale) must be a string';
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
context.returnType = 'string';
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
export function uuidTransformValidator(context: ParseContext) {
|
|
981
|
+
context.returnType = 'string';
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
export function ifNullTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
985
|
+
if (args.length !== 2) {
|
|
986
|
+
context.isValid = false;
|
|
987
|
+
context.error = 'IFNA() requires exactly 2 arguments';
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const [valueType, fallbackType] = args.map((arg) => getArgType(arg, context));
|
|
992
|
+
if (valueType !== fallbackType && valueType !== null && fallbackType !== null) {
|
|
993
|
+
context.isValid = false;
|
|
994
|
+
context.error = 'Both arguments to IFNA() must be of the same type';
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
context.returnType = valueType || fallbackType || 'string';
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
export function fromExcelDateTransformValidator(context: ParseContext, arg: ExpressionValue) {
|
|
1002
|
+
if (!arg) {
|
|
1003
|
+
context.isValid = false;
|
|
1004
|
+
context.error = 'FROMEXCELDATE() requires exactly 1 argument';
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
const argType = getArgType(arg, context);
|
|
1008
|
+
if (argType !== 'number') {
|
|
1009
|
+
context.isValid = false;
|
|
1010
|
+
context.error = 'FROMEXCELDATE() argument must be a number';
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
context.returnType = 'date';
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
export function hasTransformValidator(
|
|
1017
|
+
context: ParseContext,
|
|
1018
|
+
args: ExpressionValue[],
|
|
1019
|
+
searchValue: ExpressionValue,
|
|
1020
|
+
) {
|
|
1021
|
+
if (args.length === 0) {
|
|
1022
|
+
context.isValid = false;
|
|
1023
|
+
context.error = 'HAS() requires at least one column to check against';
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
const searchType = getArgType(searchValue, context);
|
|
1028
|
+
for (let i = 0; i < args.length; i++) {
|
|
1029
|
+
const argType = getArgType(args[i], context);
|
|
1030
|
+
if (argType !== searchType) {
|
|
1031
|
+
context.isValid = false;
|
|
1032
|
+
context.error = `Argument ${i + 1} to HAS must be of the same type as searchValue (${searchType})`;
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
context.returnType = 'number';
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
export function hasSomeTransformValidator(
|
|
1040
|
+
context: ParseContext,
|
|
1041
|
+
args: ExpressionValue[],
|
|
1042
|
+
valueArray: ExpressionValue[],
|
|
1043
|
+
) {
|
|
1044
|
+
if (args.length === 0) {
|
|
1045
|
+
context.isValid = false;
|
|
1046
|
+
context.error = 'HAS_SOME() requires at least one column to check against';
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
if (valueArray.length === 0) {
|
|
1050
|
+
context.isValid = false;
|
|
1051
|
+
context.error = 'HAS_SOME() requires at least one search value';
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
const flattenedValues: ExpressionValue[] = [];
|
|
1055
|
+
valueArray.forEach((valGroup) => {
|
|
1056
|
+
if (Array.isArray(valGroup)) {
|
|
1057
|
+
valGroup.forEach((val) => flattenedValues.push(val));
|
|
1058
|
+
} else {
|
|
1059
|
+
flattenedValues.push(valGroup);
|
|
1060
|
+
}
|
|
1061
|
+
});
|
|
1062
|
+
for (let i = 0; i < args.length; i++) {
|
|
1063
|
+
const colType = getArgType(args[i], context);
|
|
1064
|
+
for (let j = 0; j < flattenedValues.length; j++) {
|
|
1065
|
+
const valType = getArgType(flattenedValues[j], context);
|
|
1066
|
+
if (colType !== valType) {
|
|
1067
|
+
context.isValid = false;
|
|
1068
|
+
context.error = `Argument ${i + 1} and value ${j + 1} to HAS_SOME must be of the same type (${colType} vs ${valType})`;
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
context.returnType = 'number';
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
export function filterIfTransformValidator(
|
|
1078
|
+
context: ParseContext,
|
|
1079
|
+
columnArg: ExpressionValue,
|
|
1080
|
+
conditionArg: ExpressionValue,
|
|
1081
|
+
) {
|
|
1082
|
+
const colType = getArgType(columnArg, context);
|
|
1083
|
+
if (colType !== 'string' && colType !== 'number') {
|
|
1084
|
+
context.isValid = false;
|
|
1085
|
+
context.error = 'First argument to FILTER_IF must be a column reference or a valid column';
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
if (getArgType(conditionArg, context) !== 'string') {
|
|
1089
|
+
context.isValid = false;
|
|
1090
|
+
context.error = 'Second argument to FILTER_IF must be of type string';
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
context.returnType = colType;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
export function dateTransformValidator(
|
|
1097
|
+
context: ParseContext,
|
|
1098
|
+
date: ExpressionValue,
|
|
1099
|
+
format: ExpressionValue,
|
|
1100
|
+
year?: ExpressionValue,
|
|
1101
|
+
) {
|
|
1102
|
+
const dateType = getArgType(date, context);
|
|
1103
|
+
if (dateType !== 'date' && dateType !== 'string') {
|
|
1104
|
+
context.isValid = false;
|
|
1105
|
+
context.error = 'First argument to DATE must be of type date or string';
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
const formatType = getArgType(format, context);
|
|
1110
|
+
if (formatType !== 'string') {
|
|
1111
|
+
context.isValid = false;
|
|
1112
|
+
context.error = 'Second argument (format) to DATE must be of type string';
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
if (year !== undefined) {
|
|
1117
|
+
const yearType = getArgType(year, context);
|
|
1118
|
+
if (yearType !== 'number') {
|
|
1119
|
+
context.isValid = false;
|
|
1120
|
+
context.error = 'Third argument (year) to DATE must be of type number';
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
context.returnType = 'date';
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
export function switchTransformValidator(context: ParseContext, args: ExpressionValue[]) {
|
|
1129
|
+
if (args.length < 3) {
|
|
1130
|
+
context.isValid = false;
|
|
1131
|
+
context.error = 'SWITCH() requires at least 3 arguments';
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
const switchExprType = getArgType(args[0], context);
|
|
1136
|
+
if (switchExprType === null) {
|
|
1137
|
+
context.isValid = false;
|
|
1138
|
+
context.error = 'Switch expression has invalid type';
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
const remainingArgs = args.slice(1);
|
|
1143
|
+
|
|
1144
|
+
if (remainingArgs.length % 2 !== 0 && remainingArgs.length < 3) {
|
|
1145
|
+
context.isValid = false;
|
|
1146
|
+
context.error = 'SWITCH() requires at least one condition-result pair';
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
for (let i = 0; i < remainingArgs.length - (remainingArgs.length % 2); i += 2) {
|
|
1151
|
+
const condType = getArgType(remainingArgs[i], context);
|
|
1152
|
+
if (condType === null || condType !== switchExprType) {
|
|
1153
|
+
context.isValid = false;
|
|
1154
|
+
context.error = `Condition argument ${i + 2} must be of the same type as switch expression (${switchExprType})`;
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
const resultTypes: string[] = [];
|
|
1160
|
+
|
|
1161
|
+
for (let i = 1; i < remainingArgs.length - (remainingArgs.length % 2); i += 2) {
|
|
1162
|
+
const resultType = getArgType(remainingArgs[i], context);
|
|
1163
|
+
if (resultType === null) {
|
|
1164
|
+
context.isValid = false;
|
|
1165
|
+
context.error = `Result argument ${i + 2} has invalid type`;
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
resultTypes.push(resultType);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
if (remainingArgs.length % 2 === 1) {
|
|
1172
|
+
const elseType = getArgType(remainingArgs[remainingArgs.length - 1], context);
|
|
1173
|
+
if (elseType === null) {
|
|
1174
|
+
context.isValid = false;
|
|
1175
|
+
context.error = 'Else argument has invalid type';
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
resultTypes.push(elseType);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
const uniqueResultTypes = new Set(resultTypes);
|
|
1182
|
+
if (uniqueResultTypes.size > 1) {
|
|
1183
|
+
context.isValid = false;
|
|
1184
|
+
context.error = 'All result arguments to SWITCH() must be of the same type';
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
context.returnType = resultTypes[0];
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
export function hasAllTransformValidator(
|
|
1192
|
+
context: ParseContext,
|
|
1193
|
+
args: ExpressionValue[],
|
|
1194
|
+
valueArray: ExpressionValue[][],
|
|
1195
|
+
) {
|
|
1196
|
+
if (args.length === 0) {
|
|
1197
|
+
context.isValid = false;
|
|
1198
|
+
context.error = 'HAS_ALL() requires at least one column to check against';
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
if (valueArray.length === 0) {
|
|
1203
|
+
context.isValid = false;
|
|
1204
|
+
context.error = 'HAS_ALL() requires at least one search value array';
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
for (const col of args) {
|
|
1209
|
+
const colType = getArgType(col, context);
|
|
1210
|
+
if (colType === null) {
|
|
1211
|
+
context.isValid = false;
|
|
1212
|
+
context.error = 'One or more columns have invalid type';
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
for (const valGroup of valueArray) {
|
|
1218
|
+
if (!Array.isArray(valGroup) || valGroup.length === 0) {
|
|
1219
|
+
context.isValid = false;
|
|
1220
|
+
context.error = 'Each search value group must be a non-empty array';
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
for (const val of valGroup) {
|
|
1225
|
+
const valType = getArgType(val, context);
|
|
1226
|
+
if (valType === null) {
|
|
1227
|
+
context.isValid = false;
|
|
1228
|
+
context.error = 'One or more search values have invalid type';
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
context.returnType = 'number';
|
|
1235
|
+
}
|