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,114 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
import { getEntityNameFormatter } from '../utils';
|
|
4
|
+
import { FilterConfig, LogicalCombinator, Rule, RuleGroup } from './filter-types';
|
|
5
|
+
|
|
6
|
+
const FILTER_OPEATOR_MAP: Record<string, (columnName: string, value: any) => string> = {
|
|
7
|
+
'=': equalsFn,
|
|
8
|
+
IN: isOneOfFn,
|
|
9
|
+
'<>': notEqualsFn,
|
|
10
|
+
LIKE: containsFn,
|
|
11
|
+
'NOT LIKE': doesNotContainFn,
|
|
12
|
+
'IS NULL': emptyFn,
|
|
13
|
+
'IS NOT NULL': notEmptyFn,
|
|
14
|
+
'<': lessThanFn,
|
|
15
|
+
'<=': lessThanOrEqualFn,
|
|
16
|
+
'>': greaterThanFn,
|
|
17
|
+
'>=': greaterThanOrEqualFn,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Builds the filter condition for the selected columns
|
|
22
|
+
*/
|
|
23
|
+
export function buildFilterCondition(tableName: string, filterConfig: FilterConfig): string {
|
|
24
|
+
const { rules, combinator } = filterConfig;
|
|
25
|
+
const entityNameFormatter = getEntityNameFormatter();
|
|
26
|
+
return recursiveFilterBuilder(tableName, rules, combinator, entityNameFormatter);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Recursively builds the filter condition
|
|
31
|
+
*/
|
|
32
|
+
function recursiveFilterBuilder(
|
|
33
|
+
tableName: string,
|
|
34
|
+
filters: (Rule | RuleGroup)[],
|
|
35
|
+
combinator: LogicalCombinator,
|
|
36
|
+
entityNameFormatter: (name: string) => string,
|
|
37
|
+
): string {
|
|
38
|
+
return filters
|
|
39
|
+
.map((filter) => {
|
|
40
|
+
if ((filter as RuleGroup).rules) {
|
|
41
|
+
const ruleGroup = filter as RuleGroup;
|
|
42
|
+
return recursiveFilterBuilder(
|
|
43
|
+
tableName,
|
|
44
|
+
ruleGroup.rules,
|
|
45
|
+
ruleGroup.combinator,
|
|
46
|
+
entityNameFormatter,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const rule = filter as Rule;
|
|
51
|
+
const opFn = FILTER_OPEATOR_MAP[rule.operator];
|
|
52
|
+
if (!opFn) {
|
|
53
|
+
throw new Error(`Unsupported operator: ${rule.operator}`);
|
|
54
|
+
}
|
|
55
|
+
const [sanitizedColumnName, sanitizedValue] = sanitizeValue(
|
|
56
|
+
entityNameFormatter(rule.column),
|
|
57
|
+
rule.value,
|
|
58
|
+
);
|
|
59
|
+
return opFn(sanitizedColumnName, sanitizedValue);
|
|
60
|
+
})
|
|
61
|
+
.join(` ${combinator.toUpperCase()} `);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function sanitizeValue(columnName: string, value: any): [string, string] {
|
|
65
|
+
if (typeof value === 'string') {
|
|
66
|
+
return [`LOWER(${columnName})`, `'${value.toLowerCase()}'`];
|
|
67
|
+
}
|
|
68
|
+
return [columnName, value];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function equalsFn(columnName: string, value: any): string {
|
|
72
|
+
return `${columnName} = ${value}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function notEqualsFn(columnName: string, value: any): string {
|
|
76
|
+
return `${columnName} <> ${value} OR ${columnName} IS NULL`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function containsFn(columnName: string, value: any): string {
|
|
80
|
+
return `${columnName} LIKE %${value}%`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function doesNotContainFn(columnName: string, value: any): string {
|
|
84
|
+
return `${columnName} NOT LIKE %${value}% OR ${columnName} IS NULL`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function emptyFn(columnName: string): string {
|
|
88
|
+
return `${columnName} IS NULL`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function notEmptyFn(columnName: string): string {
|
|
92
|
+
return `${columnName} IS NOT NULL`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function lessThanFn(columnName: string, value: any): string {
|
|
96
|
+
return `${columnName} < ${value} OR ${columnName} IS NULL`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function lessThanOrEqualFn(columnName: string, value: any): string {
|
|
100
|
+
return `${columnName} <= ${value} OR ${columnName} IS NULL`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function greaterThanFn(columnName: string, value: any): string {
|
|
104
|
+
return `${columnName} > ${value}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function greaterThanOrEqualFn(columnName: string, value: any): string {
|
|
108
|
+
return `${columnName} >= ${value}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function isOneOfFn(columnName: string, value: string): string {
|
|
112
|
+
const values = value.split(',').map((v) => `'${v.trim()}'`);
|
|
113
|
+
return `${columnName} IN (${values.join(', ')})`;
|
|
114
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EDateRangeRelativeFilterCondition,
|
|
3
|
+
EDateRangeRelativePeriodFilterCondition,
|
|
4
|
+
} from '../query-builder/SuperFilterBuilder';
|
|
5
|
+
|
|
6
|
+
// Logical combinator for combining multiple rules
|
|
7
|
+
export type LogicalCombinator = 'and' | 'or';
|
|
8
|
+
|
|
9
|
+
// Simple filter rule (leaf node)
|
|
10
|
+
export type Rule = {
|
|
11
|
+
operator: string;
|
|
12
|
+
value: string | number | boolean | (string | number)[];
|
|
13
|
+
column: string;
|
|
14
|
+
isCategoryFilter?: boolean;
|
|
15
|
+
topNDataTarget?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Group of rules (branch node)
|
|
19
|
+
export type RuleGroup = {
|
|
20
|
+
rules: Array<Rule>;
|
|
21
|
+
combinator: LogicalCombinator;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Root filter configuration
|
|
25
|
+
export type FilterConfig = {
|
|
26
|
+
rules: Array<Rule | RuleGroup>;
|
|
27
|
+
combinator: LogicalCombinator;
|
|
28
|
+
not: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type FilterType = 'VALUES' | 'RANGE' | 'DATE' | 'RANKING';
|
|
32
|
+
|
|
33
|
+
export interface IValueFilter {
|
|
34
|
+
id: string[];
|
|
35
|
+
label: string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface IRangeFilter {
|
|
39
|
+
from?: string;
|
|
40
|
+
to?: string;
|
|
41
|
+
logicalOperator?: 'AND' | 'OR';
|
|
42
|
+
fromCondition?: string;
|
|
43
|
+
toCondition?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface IRankingFilter {
|
|
47
|
+
type: 'TOP' | 'BOTTOM' | 'BOTH';
|
|
48
|
+
rankByColumnId: string;
|
|
49
|
+
rankByColumnName: string;
|
|
50
|
+
rankByColumnType: string;
|
|
51
|
+
rankByTableName: string;
|
|
52
|
+
rankByAggregationType: string;
|
|
53
|
+
value: number;
|
|
54
|
+
isPercentage: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type IDateTimeFilter = {
|
|
58
|
+
relativeDateFilter?: EDateRangeRelativeFilterCondition;
|
|
59
|
+
period?: EDateRangeRelativePeriodFilterCondition;
|
|
60
|
+
duration?: number;
|
|
61
|
+
includeToday?: boolean;
|
|
62
|
+
fiscalYearStartMonth?: number;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export interface IGroupFilter {
|
|
66
|
+
columnIds: string[];
|
|
67
|
+
tableNames: string[];
|
|
68
|
+
columnNames: string[];
|
|
69
|
+
dataType: string[];
|
|
70
|
+
filterType: FilterType;
|
|
71
|
+
sourceType?: string[];
|
|
72
|
+
columnType?: string[];
|
|
73
|
+
columnDataType?: string[];
|
|
74
|
+
valuesFilterApplicationType?: 'exclude' | 'include';
|
|
75
|
+
valuesFilter?: IValueFilter[];
|
|
76
|
+
logicalOperator?: 'AND' | 'OR';
|
|
77
|
+
aggregationType?: string[];
|
|
78
|
+
rangeFilter?: IRangeFilter[];
|
|
79
|
+
dateTimeFilter?: IDateTimeFilter;
|
|
80
|
+
rankingFilter?: IRankingFilter[];
|
|
81
|
+
searchConfig?: { matchCase: boolean; searchString: string };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface ISuperFilterConfig {
|
|
85
|
+
groupId: string;
|
|
86
|
+
groupLabel: string;
|
|
87
|
+
condition: 'AND' | 'OR';
|
|
88
|
+
children: ({ filters: IGroupFilter } | ISuperFilterConfig)[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type RelationshipMapping = {
|
|
92
|
+
joinType: string;
|
|
93
|
+
id: string;
|
|
94
|
+
schema: string;
|
|
95
|
+
table: string;
|
|
96
|
+
joinId: string;
|
|
97
|
+
label: string;
|
|
98
|
+
alias: string;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export type JoinExpressions = {
|
|
102
|
+
alias: string;
|
|
103
|
+
joinRelation: RelationshipMapping[];
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export type RangeOperator =
|
|
107
|
+
| 'IS'
|
|
108
|
+
| 'IS_NOT'
|
|
109
|
+
| 'IS_BLANK'
|
|
110
|
+
| 'IS_NOT_BLANK'
|
|
111
|
+
| 'IS_AFTER'
|
|
112
|
+
| 'IS_BEFORE'
|
|
113
|
+
| 'IS_ON_OR_AFTER'
|
|
114
|
+
| 'IS_ON_OR_BEFORE'
|
|
115
|
+
| 'IS_LESS_THAN'
|
|
116
|
+
| 'IS_LESS_THAN_OR_EQUAL_TO'
|
|
117
|
+
| 'IS_GREATER_THAN'
|
|
118
|
+
| 'IS_GREATER_THAN_OR_EQUAL_TO'
|
|
119
|
+
| 'CONTAINS'
|
|
120
|
+
| 'DOES_NOT_CONTAIN'
|
|
121
|
+
| 'STARTS_WITH'
|
|
122
|
+
| 'DOES_NOT_START_WITH';
|
|
123
|
+
|
|
124
|
+
export interface IManualFilterOption {
|
|
125
|
+
displayName?: string;
|
|
126
|
+
value: string | number | boolean;
|
|
127
|
+
id: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface IManualFilterConfig {
|
|
131
|
+
column: string;
|
|
132
|
+
options: IManualFilterOption[];
|
|
133
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './query-builder/QueryBuilder';
|
|
2
|
+
export * from './js-lib/ParseContext';
|
|
3
|
+
export * from './js-lib/JsToSqlParser';
|
|
4
|
+
export * from './utils';
|
|
5
|
+
export * from './query-builder/SuperFilterBuilder';
|
|
6
|
+
export * from './filters/filter-types';
|
|
7
|
+
|
|
8
|
+
// epm query builder
|
|
9
|
+
export { EpmQueryBuilder } from '@epm-query-builder/EpmQueryBuilder';
|
|
10
|
+
export type { EpmQueryBuilderOptions } from '@epm-query-builder/types/query-builder-types';
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
import { ParseContext, ResolvedExpressionType, SqlQueryProps } from './ParseContext';
|
|
4
|
+
import { VisitorInterface } from './db/base/VisitorInterface';
|
|
5
|
+
import * as acorn from 'acorn';
|
|
6
|
+
import * as walk from 'acorn-walk';
|
|
7
|
+
import { CallExpressionVisitor } from './db/base/CallExpressionVisitor';
|
|
8
|
+
import { IdentifierVisitor } from './db/base/IdentifierVisitor';
|
|
9
|
+
import { LiteralVisitor } from './db/base/LiteralVisitor';
|
|
10
|
+
import { BinaryExpressionVisitor } from './db/base/BinaryExpressionVisitor';
|
|
11
|
+
import { ArrayExpressionVisitor } from './db/base/ArrayExpressionVisitor';
|
|
12
|
+
import { UnaryExpressionVisitor } from './db/base/UnaryExpressionVisitor';
|
|
13
|
+
import { ProgramVisitor } from './db/base/ProgramVisitor';
|
|
14
|
+
import { MemberExpressionVisitor } from './db/base/MemberExpressionVisitor';
|
|
15
|
+
import { generateSqlQuery } from '../sql_query_gen';
|
|
16
|
+
import { AssignmentExpressionVisitor } from './db/base/AssignmentExpressionVisitor';
|
|
17
|
+
|
|
18
|
+
export type ResolvedFormulaProps = {
|
|
19
|
+
returnType: string | undefined;
|
|
20
|
+
isValid: boolean;
|
|
21
|
+
error: string | undefined;
|
|
22
|
+
sqlQueryProps: SqlQueryProps;
|
|
23
|
+
deps: string[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Factory function to create database specific parser
|
|
28
|
+
*/
|
|
29
|
+
export function createJsToSqlParser(context: ParseContext): JsToSqlParser {
|
|
30
|
+
// Handles functions based on fabricsql type
|
|
31
|
+
return new JsToSqlParser(context);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type VisitorConfig = {
|
|
35
|
+
callExpression?: VisitorInterface<acorn.CallExpression>;
|
|
36
|
+
identifier?: VisitorInterface<acorn.Identifier>;
|
|
37
|
+
literal?: VisitorInterface<acorn.Literal>;
|
|
38
|
+
binaryExpression?: VisitorInterface<acorn.BinaryExpression>;
|
|
39
|
+
arrayExpression?: VisitorInterface<acorn.ArrayExpression>;
|
|
40
|
+
unaryExpression?: VisitorInterface<acorn.UnaryExpression>;
|
|
41
|
+
program?: VisitorInterface<acorn.Program>;
|
|
42
|
+
memberExpression?: VisitorInterface<acorn.MemberExpression>;
|
|
43
|
+
assignmentExpression?: VisitorInterface<acorn.AssignmentExpression>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parses a JavaScript formula and returns the corresponding SQL AST.
|
|
48
|
+
* - For Database specific overrides, implement the corresponding visitor in `db` directory and
|
|
49
|
+
* pass it to the constructor as part of the `config` parameter.
|
|
50
|
+
* - Use Factory function to compose parser for specific database
|
|
51
|
+
*/
|
|
52
|
+
export class JsToSqlParser {
|
|
53
|
+
private context: ParseContext;
|
|
54
|
+
private callExpression: VisitorInterface<acorn.CallExpression>;
|
|
55
|
+
private identifier: VisitorInterface<acorn.Identifier>;
|
|
56
|
+
private literal: VisitorInterface<acorn.Literal>;
|
|
57
|
+
private binaryExpression: VisitorInterface<acorn.BinaryExpression>;
|
|
58
|
+
private arrayExpression: VisitorInterface<acorn.ArrayExpression>;
|
|
59
|
+
private unaryExpression: VisitorInterface<acorn.UnaryExpression>;
|
|
60
|
+
private program: VisitorInterface<acorn.Program>;
|
|
61
|
+
private memberExpression: VisitorInterface<acorn.MemberExpression>;
|
|
62
|
+
private assignmentExpression: VisitorInterface<acorn.AssignmentExpression>;
|
|
63
|
+
|
|
64
|
+
constructor(context: ParseContext, config: VisitorConfig = {}) {
|
|
65
|
+
this.context = context;
|
|
66
|
+
this.callExpression = config.callExpression || new CallExpressionVisitor();
|
|
67
|
+
this.identifier = config.identifier || new IdentifierVisitor();
|
|
68
|
+
this.literal = config.literal || new LiteralVisitor();
|
|
69
|
+
this.binaryExpression = config.binaryExpression || new BinaryExpressionVisitor();
|
|
70
|
+
this.arrayExpression = config.arrayExpression || new ArrayExpressionVisitor();
|
|
71
|
+
this.unaryExpression = config.unaryExpression || new UnaryExpressionVisitor();
|
|
72
|
+
this.program = config.program || new ProgramVisitor();
|
|
73
|
+
this.memberExpression = config.memberExpression || new MemberExpressionVisitor();
|
|
74
|
+
this.assignmentExpression = config.assignmentExpression || new AssignmentExpressionVisitor();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
parse(formula: string): any {
|
|
78
|
+
// Parse the formula
|
|
79
|
+
const formulaText = this.processFormulaText(formula);
|
|
80
|
+
const jsAst = acorn.parse(formulaText, { ecmaVersion: 2020 });
|
|
81
|
+
|
|
82
|
+
// Traverse the AST in pre-order to check for 'if' statements
|
|
83
|
+
this.detectIfCondition(jsAst);
|
|
84
|
+
|
|
85
|
+
// Traverse the AST and generate SQL AST
|
|
86
|
+
walk.recursive(jsAst, this.context.reset(), {
|
|
87
|
+
CallExpression: (node, state, c) => {
|
|
88
|
+
c(node.callee, state);
|
|
89
|
+
node.arguments.forEach((arg) => c(arg, state));
|
|
90
|
+
this.callExpression.visitor(node, state);
|
|
91
|
+
},
|
|
92
|
+
Identifier: (node, state) => {
|
|
93
|
+
this.identifier.visitor(node, state);
|
|
94
|
+
},
|
|
95
|
+
Literal: (node, state) => {
|
|
96
|
+
this.literal.visitor(node, state);
|
|
97
|
+
},
|
|
98
|
+
BinaryExpression: (node, state, c) => {
|
|
99
|
+
c(node.left, state);
|
|
100
|
+
c(node.right, state);
|
|
101
|
+
this.binaryExpression.visitor(node, state);
|
|
102
|
+
},
|
|
103
|
+
AssignmentExpression: (node, state, c) => {
|
|
104
|
+
c(node.left, state);
|
|
105
|
+
c(node.right, state);
|
|
106
|
+
this.assignmentExpression.visitor(node, state);
|
|
107
|
+
},
|
|
108
|
+
ArrayExpression: (node, state, c) => {
|
|
109
|
+
node.elements.forEach((el) => {
|
|
110
|
+
if (el !== null) c(el, state);
|
|
111
|
+
});
|
|
112
|
+
this.arrayExpression.visitor(node, state);
|
|
113
|
+
},
|
|
114
|
+
UnaryExpression: (node, state, c) => {
|
|
115
|
+
c(node.argument, state);
|
|
116
|
+
this.unaryExpression.visitor(node, state);
|
|
117
|
+
},
|
|
118
|
+
MemberExpression: (node, state, c) => {
|
|
119
|
+
c(node.object, state);
|
|
120
|
+
if (node.computed) c(node.property, state);
|
|
121
|
+
this.memberExpression.visitor(node, state);
|
|
122
|
+
},
|
|
123
|
+
Program: (node, state, c) => {
|
|
124
|
+
node.body.forEach((statement) => c(statement, state));
|
|
125
|
+
this.program.visitor(node, state);
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
const sqlAst = this.context.getLastEvaluatedValue();
|
|
129
|
+
return sqlAst;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Converts the SQL AST to a SQL query string
|
|
134
|
+
*/
|
|
135
|
+
toSql(sqlAst: any): string {
|
|
136
|
+
return generateSqlQuery(sqlAst);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Creates appropriate SQL query props based on the SQL AST
|
|
141
|
+
*/
|
|
142
|
+
toSqlProps(sqlAst: any): SqlQueryProps {
|
|
143
|
+
const sqlQueryStr = this.toSql(sqlAst);
|
|
144
|
+
|
|
145
|
+
if (this.context.cteCount > 0) {
|
|
146
|
+
return {
|
|
147
|
+
resolvedExpression: {
|
|
148
|
+
type: ResolvedExpressionType.CTE,
|
|
149
|
+
cteName: `cte_${this.context.currentColumnId}`,
|
|
150
|
+
value: [sqlQueryStr],
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
resolvedExpression: {
|
|
157
|
+
type: ResolvedExpressionType.COLUMN,
|
|
158
|
+
value: [sqlQueryStr],
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Returns the resolved formula props for current column along with the dependencies
|
|
165
|
+
*/
|
|
166
|
+
getResolvedFormulaProps(sqlAst: any): ResolvedFormulaProps {
|
|
167
|
+
const sqlQueryProps = this.toSqlProps(sqlAst);
|
|
168
|
+
return {
|
|
169
|
+
sqlQueryProps,
|
|
170
|
+
deps: Array.from(this.context.getColumnDeps()),
|
|
171
|
+
returnType: this.context.returnType,
|
|
172
|
+
isValid: this.context.isValid,
|
|
173
|
+
error: this.context.error,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Pre walk and detect if the jsAst has 'if'
|
|
179
|
+
*/
|
|
180
|
+
private detectIfCondition(jsAst: acorn.Node): void {
|
|
181
|
+
walk.simple(jsAst, {
|
|
182
|
+
CallExpression: (node: acorn.CallExpression) => {
|
|
183
|
+
if (node.callee.type === 'Identifier' && node.callee.name.toUpperCase() === 'IF') {
|
|
184
|
+
this.context.ifCondition = true;
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Extracts and normalizes formula by adding parentheses to reserved function names
|
|
192
|
+
*/
|
|
193
|
+
private processFormulaText(formula: string): string {
|
|
194
|
+
// Extract formula from {{ ... }} or use the string as-is
|
|
195
|
+
const formulaText = formula?.match(/{{([^}]*)}}/)?.[1] ?? formula;
|
|
196
|
+
|
|
197
|
+
// Reserved function names to patch
|
|
198
|
+
const reservedFunctions = ['NOW', 'TODAY', 'UUID', 'RAND'];
|
|
199
|
+
|
|
200
|
+
// Patch function names not followed by '(' to add ()
|
|
201
|
+
let patched = formulaText;
|
|
202
|
+
for (const fn of reservedFunctions) {
|
|
203
|
+
const regex = new RegExp(`\\b${fn}\\b(?!\\s*\\()`, 'gi');
|
|
204
|
+
patched = patched.replace(regex, `${fn}()`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (formulaText.includes('FOREACH')) {
|
|
208
|
+
patched = this.removeForeach(formula);
|
|
209
|
+
}
|
|
210
|
+
return patched;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private removeForeach(input: string): string {
|
|
214
|
+
const foreachRegex = /FOREACH\(([^,]*),([^()]*)\)/g;
|
|
215
|
+
return input.replace(foreachRegex, '$2');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
import * as acorn from 'acorn';
|
|
4
|
+
import {
|
|
5
|
+
getEntityNameFormatter,
|
|
6
|
+
getFormulaIdColumnMap,
|
|
7
|
+
getDeprecatedFormulaIdColumnMap,
|
|
8
|
+
} from '../utils';
|
|
9
|
+
|
|
10
|
+
export enum MDM_COLUMN_TYPE {
|
|
11
|
+
TEXT = 1,
|
|
12
|
+
SINGLE_SELECT = 2,
|
|
13
|
+
MULTI_SELECT = 3,
|
|
14
|
+
DATE = 4,
|
|
15
|
+
COMMENTS = 5,
|
|
16
|
+
NUMBER = 6,
|
|
17
|
+
PERSON = 7,
|
|
18
|
+
TIME = 8,
|
|
19
|
+
LAST_UPDATED_BY = 9,
|
|
20
|
+
LAST_UPDATED_AT = 10,
|
|
21
|
+
CHECKBOX = 11,
|
|
22
|
+
DATETIME = 12,
|
|
23
|
+
DECIMAL = 13,
|
|
24
|
+
IMAGE = 14,
|
|
25
|
+
URL = 15,
|
|
26
|
+
EMAIL = 16,
|
|
27
|
+
FORMULA = 17,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export enum ResolvedExpressionType {
|
|
31
|
+
COLUMN = 'columnExpr',
|
|
32
|
+
CTE = 'cteExpr',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type CteExpression = {
|
|
36
|
+
type: ResolvedExpressionType.CTE;
|
|
37
|
+
cteName: string;
|
|
38
|
+
value: string[];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type ColumnExpression = {
|
|
42
|
+
type: ResolvedExpressionType.COLUMN;
|
|
43
|
+
value: string[];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type SqlQueryProps = {
|
|
47
|
+
resolvedExpression: ColumnExpression | CteExpression;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type ColumnMeta = {
|
|
51
|
+
sqlQueryProps?: SqlQueryProps;
|
|
52
|
+
computationOrder?: number;
|
|
53
|
+
deps?: string[];
|
|
54
|
+
[key: string]: any;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// This is mock interface for column config. Actual type comes from InfoRiverMDM repo from type `IMDMColumnConfigWithParsedMeta`
|
|
58
|
+
export interface IMDMColumnConfigWithParsedMeta {
|
|
59
|
+
columnName: string;
|
|
60
|
+
columnType: MDM_COLUMN_TYPE;
|
|
61
|
+
columnMeta: ColumnMeta;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type TColumnConfigMap = Record<string, IMDMColumnConfigWithParsedMeta>;
|
|
65
|
+
|
|
66
|
+
export type ParseContextProps = {
|
|
67
|
+
columnConfigMap: TColumnConfigMap;
|
|
68
|
+
currentColumnId: string;
|
|
69
|
+
primaryKeyColumns: string[];
|
|
70
|
+
tableName: string;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export class ParseContext {
|
|
74
|
+
private lastEvaluatedValue: any;
|
|
75
|
+
private _cteCount: number = 0;
|
|
76
|
+
public formulaIdColumnMap: Record<string, string>;
|
|
77
|
+
public deprecatedFormulaColumnMap: Record<string, string>;
|
|
78
|
+
public ifCondition: boolean = false;
|
|
79
|
+
private readonly columnDeps: Set<string>;
|
|
80
|
+
public readonly state: Map<string, any>;
|
|
81
|
+
public readonly columnConfigMap: TColumnConfigMap;
|
|
82
|
+
public readonly currentColumnId: string;
|
|
83
|
+
public readonly primaryKeyColumns: string[];
|
|
84
|
+
public readonly tableName: string;
|
|
85
|
+
public readonly entityNameFormatter: (name: string) => string;
|
|
86
|
+
public returnType: string | undefined;
|
|
87
|
+
public isValid: boolean = true;
|
|
88
|
+
public error: string | undefined;
|
|
89
|
+
|
|
90
|
+
constructor(props: ParseContextProps) {
|
|
91
|
+
this.state = new Map();
|
|
92
|
+
this.lastEvaluatedValue = null;
|
|
93
|
+
this.columnConfigMap = props.columnConfigMap;
|
|
94
|
+
this.formulaIdColumnMap = getFormulaIdColumnMap(props.columnConfigMap);
|
|
95
|
+
this.deprecatedFormulaColumnMap = getDeprecatedFormulaIdColumnMap(props.columnConfigMap);
|
|
96
|
+
this.currentColumnId = props.currentColumnId;
|
|
97
|
+
this.primaryKeyColumns = props.primaryKeyColumns;
|
|
98
|
+
this.tableName = props.tableName;
|
|
99
|
+
this.columnDeps = new Set<string>();
|
|
100
|
+
this.entityNameFormatter = getEntityNameFormatter();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Reset the parse context
|
|
105
|
+
*/
|
|
106
|
+
reset(): ParseContext {
|
|
107
|
+
this.lastEvaluatedValue = null;
|
|
108
|
+
this.state.clear();
|
|
109
|
+
this.columnDeps.clear();
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get(node: acorn.Node): any {
|
|
114
|
+
return this.state.get(this.getId(node));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
set(node: acorn.Node, value: any): void {
|
|
118
|
+
this.lastEvaluatedValue = value;
|
|
119
|
+
this.state.set(this.getId(node), value);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getId(node: acorn.Node): string {
|
|
123
|
+
return `${node.start}_${node.end}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getLastEvaluatedValue(): any {
|
|
127
|
+
return this.lastEvaluatedValue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getColumnCount(): number {
|
|
131
|
+
return Object.keys(this.columnConfigMap).length;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
addColumnDep(columnName: string): void {
|
|
135
|
+
this.columnDeps.add(columnName);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getColumnDeps(): Set<string> {
|
|
139
|
+
return this.columnDeps;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get cteCount(): number {
|
|
143
|
+
return this._cteCount;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
incrementCTECount(): void {
|
|
147
|
+
this._cteCount++;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { VisitorInterface } from './VisitorInterface';
|
|
2
|
+
import * as acorn from 'acorn';
|
|
3
|
+
import { ParseContext } from '../../ParseContext';
|
|
4
|
+
|
|
5
|
+
export class ArrayExpressionVisitor implements VisitorInterface<acorn.ArrayExpression> {
|
|
6
|
+
/**
|
|
7
|
+
* visitor needs to be implemented as arrow function to avoid `this` binding issue since it will be
|
|
8
|
+
* passed to `acorn-walk` library
|
|
9
|
+
*/
|
|
10
|
+
public visitor = (node: acorn.ArrayExpression, context: ParseContext) => {
|
|
11
|
+
context.set(
|
|
12
|
+
node,
|
|
13
|
+
node.elements.map((arg) => context.get(arg as acorn.Node)),
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { VisitorInterface } from './VisitorInterface';
|
|
2
|
+
import * as acorn from 'acorn';
|
|
3
|
+
import { ParseContext } from '../../ParseContext';
|
|
4
|
+
import { toBinaryExpression } from '../../../sql-lib/binary_expr';
|
|
5
|
+
import { PctObject } from '../../objects/PctObject';
|
|
6
|
+
import { ExpressionValue } from '../../../sql-types';
|
|
7
|
+
import { getArgType } from '@/utils';
|
|
8
|
+
|
|
9
|
+
export class AssignmentExpressionVisitor implements VisitorInterface<acorn.AssignmentExpression> {
|
|
10
|
+
public visitor = (node: acorn.AssignmentExpression, context: ParseContext) => {
|
|
11
|
+
const operator = node.operator;
|
|
12
|
+
|
|
13
|
+
// We're only treating "=" as comparison
|
|
14
|
+
if (operator !== '=') {
|
|
15
|
+
context.isValid = false;
|
|
16
|
+
context.error = `Unsupported assignment operator: "${operator}"`;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const lhs = context.get(node.left) as ExpressionValue;
|
|
20
|
+
const rhs = context.get(node.right) as ExpressionValue;
|
|
21
|
+
if (getArgType(lhs, context) !== getArgType(rhs, context)) {
|
|
22
|
+
context.isValid = false;
|
|
23
|
+
context.error = `Expected both sides dataType to be same`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (rhs instanceof PctObject) {
|
|
27
|
+
context.set(node, rhs.resolve(lhs, { type: 'string', value: '=' }));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const expr = toBinaryExpression('=', lhs, rhs, false);
|
|
32
|
+
context.set(node, expr);
|
|
33
|
+
};
|
|
34
|
+
}
|