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,628 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JoinExpressions,
|
|
3
|
+
RangeOperator,
|
|
4
|
+
ISuperFilterConfig,
|
|
5
|
+
IGroupFilter,
|
|
6
|
+
IManualFilterConfig,
|
|
7
|
+
IManualFilterOption,
|
|
8
|
+
} from '../filters/filter-types';
|
|
9
|
+
import { DateFilterFactory } from '../superFilter/DateFilterFactory';
|
|
10
|
+
import { getEntityNameFormatter, getFormattedTableName } from '../utils';
|
|
11
|
+
import { MAX_STRING_TYPE } from './QueryBuilder';
|
|
12
|
+
|
|
13
|
+
export enum EDateRangeRelativeFilterCondition {
|
|
14
|
+
IS_IN_THE_LAST = 'IS_IN_THE_LAST',
|
|
15
|
+
IS_IN_THIS = 'IS_IN_THIS',
|
|
16
|
+
IS_IN_THE_NEXT = 'IS_IN_THE_NEXT',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export enum EDateRangeRelativePeriodFilterCondition {
|
|
20
|
+
DAYS = 'DAYS',
|
|
21
|
+
WEEKS = 'WEEKS',
|
|
22
|
+
CALENDER_WEEKS = 'CALENDER_WEEKS',
|
|
23
|
+
MONTHS = 'MONTHS',
|
|
24
|
+
CALENDER_MONTHS = 'CALENDER_MONTHS',
|
|
25
|
+
YEARS = 'YEARS',
|
|
26
|
+
CALENDER_YEARS = 'CALENDER_YEARS',
|
|
27
|
+
HOURS = 'HOURS',
|
|
28
|
+
MINUTES = 'MINUTES',
|
|
29
|
+
CALENDER_QUARTERS = 'CALENDER_QUARTERS',
|
|
30
|
+
FISCAL_QUARTER = 'FISCAL_QUARTER',
|
|
31
|
+
FISCAL_YEAR = 'FISCAL_YEAR',
|
|
32
|
+
QUARTERS = 'QUARTERS',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const rangeFilterOperator: Record<RangeOperator, string> = {
|
|
36
|
+
// common operators
|
|
37
|
+
IS: '=',
|
|
38
|
+
IS_NOT: '!=',
|
|
39
|
+
IS_BLANK: 'IS',
|
|
40
|
+
IS_NOT_BLANK: 'IS NOT',
|
|
41
|
+
//date specific operators
|
|
42
|
+
IS_AFTER: '>',
|
|
43
|
+
IS_BEFORE: '<',
|
|
44
|
+
IS_ON_OR_AFTER: '>=',
|
|
45
|
+
IS_ON_OR_BEFORE: '<=',
|
|
46
|
+
//numeric specific operators
|
|
47
|
+
IS_LESS_THAN: '<',
|
|
48
|
+
IS_LESS_THAN_OR_EQUAL_TO: '<=',
|
|
49
|
+
IS_GREATER_THAN: '>',
|
|
50
|
+
IS_GREATER_THAN_OR_EQUAL_TO: '>=',
|
|
51
|
+
//character specific operators
|
|
52
|
+
CONTAINS: 'LIKE',
|
|
53
|
+
DOES_NOT_CONTAIN: 'NOT LIKE',
|
|
54
|
+
STARTS_WITH: 'LIKE',
|
|
55
|
+
DOES_NOT_START_WITH: 'NOT LIKE',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const characterRangeFilterOperator = [
|
|
59
|
+
'CONTAINS',
|
|
60
|
+
'DOES_NOT_CONTAIN',
|
|
61
|
+
'STARTS_WITH',
|
|
62
|
+
'DOES_NOT_START_WITH',
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
export const negativeCharacterOperators: RangeOperator[] = [
|
|
66
|
+
'DOES_NOT_CONTAIN',
|
|
67
|
+
'DOES_NOT_START_WITH',
|
|
68
|
+
'IS_NOT',
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
export const startsWithCharacterOperators: RangeOperator[] = ['STARTS_WITH', 'DOES_NOT_START_WITH'];
|
|
72
|
+
|
|
73
|
+
export const containsCharacterOperators: RangeOperator[] = ['CONTAINS', 'DOES_NOT_CONTAIN'];
|
|
74
|
+
|
|
75
|
+
const SUPER_FILTER_NUMERIC_SUPPORTED_DATA_TYPES = [
|
|
76
|
+
'Int64',
|
|
77
|
+
'Decimal',
|
|
78
|
+
'Double',
|
|
79
|
+
'Integer',
|
|
80
|
+
'Number',
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
export enum EFilterDataType {
|
|
84
|
+
BOOLEAN = 'boolean',
|
|
85
|
+
DATE = 'date',
|
|
86
|
+
NUMBER = 'number',
|
|
87
|
+
STRING = 'string',
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Base class for super filter builder
|
|
91
|
+
export class SuperFilterBuilder {
|
|
92
|
+
private superFilter: ISuperFilterConfig;
|
|
93
|
+
private databaseDetails: any;
|
|
94
|
+
private skipCountForRankingFilter: boolean;
|
|
95
|
+
private joinClauses: JoinExpressions;
|
|
96
|
+
private manualFilterOptions: IManualFilterConfig[];
|
|
97
|
+
|
|
98
|
+
// new: the selected (last) ranking filter across the whole payload
|
|
99
|
+
private lastRankingFilter: IGroupFilter | null = null;
|
|
100
|
+
|
|
101
|
+
constructor(
|
|
102
|
+
superFilter: ISuperFilterConfig,
|
|
103
|
+
databaseDetails: any,
|
|
104
|
+
skipCountForRankingFilter: boolean = false,
|
|
105
|
+
joinClauses: JoinExpressions = { alias: '', joinRelation: [] },
|
|
106
|
+
manualFilterOptions: IManualFilterConfig[] = [],
|
|
107
|
+
) {
|
|
108
|
+
this.superFilter = superFilter;
|
|
109
|
+
this.databaseDetails = databaseDetails;
|
|
110
|
+
this.skipCountForRankingFilter = skipCountForRankingFilter;
|
|
111
|
+
this.joinClauses = joinClauses;
|
|
112
|
+
this.manualFilterOptions = manualFilterOptions;
|
|
113
|
+
|
|
114
|
+
// find the last ranking filter in the whole payload and store a reference
|
|
115
|
+
this.lastRankingFilter = this.findLastRankingFilter(this.superFilter);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Entry point: build SQL condition string
|
|
120
|
+
*/
|
|
121
|
+
public build(): string {
|
|
122
|
+
const whereCondition = this.processGroup(this.superFilter, true, this.lastRankingFilter);
|
|
123
|
+
|
|
124
|
+
//appending ranking filter at the end of the where condition.
|
|
125
|
+
if (this.lastRankingFilter && !this.skipCountForRankingFilter) {
|
|
126
|
+
// wrap existing where in parentheses to pass as a single expression to ranking
|
|
127
|
+
const existingWhere = whereCondition ? `(${whereCondition})` : '';
|
|
128
|
+
const rankingCondition = this.processRankingFilter(this.lastRankingFilter);
|
|
129
|
+
|
|
130
|
+
if (!whereCondition) {
|
|
131
|
+
// no other filters, return ranking condition
|
|
132
|
+
return rankingCondition;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ensure ranking condition is appended at the end
|
|
136
|
+
return `${existingWhere} AND ${rankingCondition}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return whereCondition;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Recursively process group and children
|
|
144
|
+
* - skips all ranking filters during this pass
|
|
145
|
+
* - preserves order of all other filters
|
|
146
|
+
*/
|
|
147
|
+
private processGroup(
|
|
148
|
+
group: any,
|
|
149
|
+
isRoot = false,
|
|
150
|
+
lastRankingToSkip: IGroupFilter | null = null,
|
|
151
|
+
): string {
|
|
152
|
+
if (!group?.children) throw new Error('No childrens found');
|
|
153
|
+
|
|
154
|
+
const parts: string[] = [];
|
|
155
|
+
|
|
156
|
+
for (const child of group.children) {
|
|
157
|
+
if ('groupId' in child && 'children' in child) {
|
|
158
|
+
const nested = this.processGroup(child, false, lastRankingToSkip);
|
|
159
|
+
if (nested) parts.push(nested);
|
|
160
|
+
} else if ('filters' in child) {
|
|
161
|
+
const filter = child.filters as IGroupFilter;
|
|
162
|
+
|
|
163
|
+
if (filter.sourceType?.[0] !== 'powerTables') throw new Error('Unsupported source type');
|
|
164
|
+
|
|
165
|
+
if (filter.filterType === 'RANKING') continue;
|
|
166
|
+
|
|
167
|
+
const condition = this.processFilter(filter);
|
|
168
|
+
if (condition) parts.push(condition);
|
|
169
|
+
const searchCondition = this.processSearchFilter(filter);
|
|
170
|
+
if (searchCondition) parts.push(searchCondition);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (parts.length === 0) return '';
|
|
175
|
+
|
|
176
|
+
const joined = parts.join(` ${group.condition ?? 'AND'} `);
|
|
177
|
+
|
|
178
|
+
return isRoot ? joined : `(${joined})`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Find the last ranking filter in the whole superFilter (depth-first, left-to-right traversal)
|
|
183
|
+
*/
|
|
184
|
+
private findLastRankingFilter(group: any): IGroupFilter | null {
|
|
185
|
+
if (!group?.children) return null;
|
|
186
|
+
|
|
187
|
+
let last: IGroupFilter | null = null;
|
|
188
|
+
|
|
189
|
+
for (const child of group.children) {
|
|
190
|
+
if ('groupId' in child && 'children' in child) {
|
|
191
|
+
const found = this.findLastRankingFilter(child);
|
|
192
|
+
if (found) last = found;
|
|
193
|
+
} else if ('filters' in child) {
|
|
194
|
+
if (child.filters.filterType === 'RANKING') {
|
|
195
|
+
last = child.filters as IGroupFilter;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return last;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Decide which filter type to handle
|
|
205
|
+
*/
|
|
206
|
+
private processFilter(filter: IGroupFilter): string {
|
|
207
|
+
switch (filter.filterType) {
|
|
208
|
+
case 'VALUES':
|
|
209
|
+
return this.processValuesFilter(filter);
|
|
210
|
+
case 'RANGE':
|
|
211
|
+
return this.processRangeFilter(filter);
|
|
212
|
+
case 'DATE': {
|
|
213
|
+
const column = this.getColumnName(filter);
|
|
214
|
+
return DateFilterFactory.build(column, filter);
|
|
215
|
+
}
|
|
216
|
+
case 'RANKING':
|
|
217
|
+
// ranking filters are intentionally ignored here; they are processed in build()
|
|
218
|
+
return '';
|
|
219
|
+
default:
|
|
220
|
+
if (!filter.searchConfig) {
|
|
221
|
+
throw new Error(`Unsupported filter type: ${filter.filterType}`);
|
|
222
|
+
}
|
|
223
|
+
return '';
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Handle VALUES filter => column IN/NOT IN (...)
|
|
229
|
+
*/
|
|
230
|
+
private processValuesFilter(filter: IGroupFilter): string {
|
|
231
|
+
if (!filter.valuesFilter || filter.valuesFilter.length === 0)
|
|
232
|
+
throw new Error('Values filter not found');
|
|
233
|
+
const column = this.getColumnName(filter);
|
|
234
|
+
const values = filter.valuesFilter.flatMap((v) => v.id);
|
|
235
|
+
|
|
236
|
+
const include = filter.valuesFilterApplicationType === 'include';
|
|
237
|
+
const nonBlankValues = values.filter((v) => v !== '(Blank)' && v !== null);
|
|
238
|
+
const hasBlank = values.length !== nonBlankValues.length;
|
|
239
|
+
|
|
240
|
+
const formattedValues = nonBlankValues
|
|
241
|
+
.map((v) => this.formatValue(v, this.getFilterDataType(filter)))
|
|
242
|
+
.join(', ');
|
|
243
|
+
|
|
244
|
+
const parts = [];
|
|
245
|
+
if (nonBlankValues.length) {
|
|
246
|
+
parts.push(`${column} ${include ? 'IN' : 'NOT IN'} (${formattedValues})`);
|
|
247
|
+
}
|
|
248
|
+
if (hasBlank) {
|
|
249
|
+
let baseFilter = `${column} IS ${include ? '' : 'NOT '}NULL`;
|
|
250
|
+
|
|
251
|
+
if (filter.dataType?.[0] === EFilterDataType.STRING) {
|
|
252
|
+
baseFilter = `${baseFilter} OR ${column} = ''`;
|
|
253
|
+
}
|
|
254
|
+
parts.push(baseFilter);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return `(${parts.join(include ? ' OR ' : ' AND')})`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Handle RANGE filter => column op value AND/OR column op value
|
|
262
|
+
*/
|
|
263
|
+
|
|
264
|
+
private processRangeFilter(filter: IGroupFilter): string {
|
|
265
|
+
if (!filter.rangeFilter || filter.rangeFilter.length === 0)
|
|
266
|
+
throw new Error('Range filter not found');
|
|
267
|
+
|
|
268
|
+
const column = this.getColumnName(filter);
|
|
269
|
+
const { rangeFilter } = filter;
|
|
270
|
+
|
|
271
|
+
const allExpressions: string[] = [];
|
|
272
|
+
|
|
273
|
+
const columnName = filter.columnNames?.[0] ?? filter.columnIds?.[0];
|
|
274
|
+
const manualConfig = this.manualFilterOptions?.find((opt) => opt.column === columnName);
|
|
275
|
+
|
|
276
|
+
for (const range of rangeFilter) {
|
|
277
|
+
const parts: string[] = [];
|
|
278
|
+
const hasFrom = range.from !== undefined && range.fromCondition !== undefined;
|
|
279
|
+
const hasTo = range.to !== undefined && range.toCondition !== undefined;
|
|
280
|
+
|
|
281
|
+
const dataType = this.getFilterDataType(filter);
|
|
282
|
+
|
|
283
|
+
// Handle "from"
|
|
284
|
+
if (hasFrom) {
|
|
285
|
+
const op = rangeFilterOperator[range.fromCondition as RangeOperator];
|
|
286
|
+
const isCharacterFilter = characterRangeFilterOperator.includes(
|
|
287
|
+
range.fromCondition as RangeOperator,
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
if (isCharacterFilter) {
|
|
291
|
+
if (manualConfig) {
|
|
292
|
+
const manualMatch = this.getManualFilterMatch(
|
|
293
|
+
range.from,
|
|
294
|
+
filter,
|
|
295
|
+
range.fromCondition as RangeOperator,
|
|
296
|
+
manualConfig,
|
|
297
|
+
);
|
|
298
|
+
parts.push(manualMatch);
|
|
299
|
+
} else {
|
|
300
|
+
parts.push(
|
|
301
|
+
this.formatRelativeCharacterFilter(
|
|
302
|
+
column,
|
|
303
|
+
range.fromCondition as RangeOperator,
|
|
304
|
+
|
|
305
|
+
range.from,
|
|
306
|
+
),
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
const formattedValue = this.formatValue(range.from, dataType);
|
|
311
|
+
let baseFilter = `${column} ${op} ${formattedValue}`;
|
|
312
|
+
const { isBlankOperator, isNotBlankOperator } = this.getOperatorFlags(
|
|
313
|
+
range.fromCondition as RangeOperator,
|
|
314
|
+
);
|
|
315
|
+
if (isBlankOperator && dataType === EFilterDataType.STRING) {
|
|
316
|
+
baseFilter = `${baseFilter} OR ${column} = ''`;
|
|
317
|
+
}
|
|
318
|
+
if (isNotBlankOperator && dataType === EFilterDataType.STRING) {
|
|
319
|
+
baseFilter = `${baseFilter} AND ${column} <> ''`;
|
|
320
|
+
}
|
|
321
|
+
parts.push(baseFilter);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Handle "to"
|
|
326
|
+
if (hasTo) {
|
|
327
|
+
const op = rangeFilterOperator[range.toCondition as RangeOperator];
|
|
328
|
+
const isCharacterFilter = characterRangeFilterOperator.includes(
|
|
329
|
+
range.toCondition as RangeOperator,
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
if (isCharacterFilter) {
|
|
333
|
+
if (manualConfig) {
|
|
334
|
+
const manualMatch = this.getManualFilterMatch(
|
|
335
|
+
range.to,
|
|
336
|
+
filter,
|
|
337
|
+
range.toCondition as RangeOperator,
|
|
338
|
+
manualConfig,
|
|
339
|
+
);
|
|
340
|
+
parts.push(manualMatch);
|
|
341
|
+
} else {
|
|
342
|
+
parts.push(
|
|
343
|
+
this.formatRelativeCharacterFilter(
|
|
344
|
+
column,
|
|
345
|
+
range.toCondition as RangeOperator,
|
|
346
|
+
range.to,
|
|
347
|
+
),
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
const formattedValue = this.formatValue(range.to, dataType);
|
|
352
|
+
let baseFilter = `${column} ${op} ${formattedValue}`;
|
|
353
|
+
|
|
354
|
+
const { isBlankOperator, isNotBlankOperator } = this.getOperatorFlags(
|
|
355
|
+
range.fromCondition as RangeOperator,
|
|
356
|
+
);
|
|
357
|
+
if (isBlankOperator && dataType === EFilterDataType.STRING) {
|
|
358
|
+
baseFilter = `${baseFilter} OR ${column} = ''`;
|
|
359
|
+
}
|
|
360
|
+
if (isNotBlankOperator && dataType === EFilterDataType.STRING) {
|
|
361
|
+
baseFilter = `${baseFilter} AND ${column} <> ''`;
|
|
362
|
+
}
|
|
363
|
+
parts.push(baseFilter);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (parts.length > 0) {
|
|
368
|
+
// If both exist and this range specifies a logicalOperator join with that
|
|
369
|
+
if (hasFrom && hasTo && range.logicalOperator) {
|
|
370
|
+
allExpressions.push(`(${parts.join(` ${range.logicalOperator.toUpperCase()} `)})`);
|
|
371
|
+
} else if (parts.length === 1) {
|
|
372
|
+
allExpressions.push(parts[0]);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (allExpressions.length === 0) return '';
|
|
378
|
+
|
|
379
|
+
// Top-level join fallback to filter.logicalOperator OR default AND
|
|
380
|
+
return `(${allExpressions.join(` ${filter.logicalOperator?.toUpperCase() ?? 'AND'} `)})`;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Handle RANKING filter (top/bottom/both)
|
|
385
|
+
*/
|
|
386
|
+
|
|
387
|
+
private processRankingFilter(filter: IGroupFilter): string {
|
|
388
|
+
if (!filter.rankingFilter || filter.rankingFilter.length === 0) {
|
|
389
|
+
throw new Error('Ranking filter not found');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const { rankingFilter } = filter;
|
|
393
|
+
const subQueries: string[] = [];
|
|
394
|
+
const dataType = filter.dataType?.[0];
|
|
395
|
+
const formatEntity = getEntityNameFormatter();
|
|
396
|
+
|
|
397
|
+
// Step 1: Build table name without alias
|
|
398
|
+
const tableName = getFormattedTableName(this.databaseDetails);
|
|
399
|
+
|
|
400
|
+
// Step 2: Derive safe column names
|
|
401
|
+
const targetColumn = this.getColumnName(filter);
|
|
402
|
+
|
|
403
|
+
for (const rank of rankingFilter) {
|
|
404
|
+
const { type, value, isPercentage, rankByColumnId } = rank;
|
|
405
|
+
|
|
406
|
+
const rankByColumn = formatEntity(rankByColumnId, dataType);
|
|
407
|
+
const limitCondition = isPercentage
|
|
408
|
+
? `CAST(ROUND(COUNT(*) * ${value} / 100.0) AS INT)`
|
|
409
|
+
: `${value}`;
|
|
410
|
+
|
|
411
|
+
const whereParts: string[] = [`${rankByColumn} IS NOT NULL`];
|
|
412
|
+
if (targetColumn !== rankByColumn) {
|
|
413
|
+
whereParts.push(`${targetColumn} IS NOT NULL`);
|
|
414
|
+
}
|
|
415
|
+
const finalWhere = whereParts.length > 0 ? `WHERE ${whereParts.join(' AND ')}` : '';
|
|
416
|
+
|
|
417
|
+
// Build TOP subquery if needed
|
|
418
|
+
if (type === 'TOP' || type === 'BOTH') {
|
|
419
|
+
subQueries.push(`
|
|
420
|
+
${targetColumn} IN (
|
|
421
|
+
SELECT ranked.${targetColumn}
|
|
422
|
+
FROM (
|
|
423
|
+
SELECT ${targetColumn},
|
|
424
|
+
DENSE_RANK() OVER (ORDER BY ${rankByColumn} DESC) AS rn
|
|
425
|
+
FROM ${tableName}
|
|
426
|
+
${finalWhere}
|
|
427
|
+
) ranked
|
|
428
|
+
WHERE rn <= ${limitCondition}
|
|
429
|
+
)
|
|
430
|
+
`);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Build BOTTOM subquery if needed
|
|
434
|
+
if (type === 'BOTTOM' || type === 'BOTH') {
|
|
435
|
+
subQueries.push(`
|
|
436
|
+
${targetColumn} IN (
|
|
437
|
+
SELECT ranked.${targetColumn}
|
|
438
|
+
FROM (
|
|
439
|
+
SELECT ${targetColumn},
|
|
440
|
+
DENSE_RANK() OVER (ORDER BY ${rankByColumn} ASC) AS rn
|
|
441
|
+
FROM ${tableName}
|
|
442
|
+
${finalWhere}
|
|
443
|
+
) ranked
|
|
444
|
+
WHERE rn <= ${limitCondition}
|
|
445
|
+
)
|
|
446
|
+
`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Join TOP/BOTTOM subqueries with OR, wrap them to maintain AND order
|
|
451
|
+
return `(${subQueries.join(' OR ')})`;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Resolve column name (table.column or column only)
|
|
456
|
+
*/
|
|
457
|
+
private getColumnName(filter: IGroupFilter): string {
|
|
458
|
+
const { alias, joinRelation = [] } = this.joinClauses || {};
|
|
459
|
+
let mainTableAlias = alias;
|
|
460
|
+
let col = filter.columnNames?.[0] ?? filter.columnIds?.[0];
|
|
461
|
+
// If any join.id matches the column, use join.id instead join.label and alias
|
|
462
|
+
const matchingJoin = joinRelation.find((join) => join.id === col);
|
|
463
|
+
if (matchingJoin) {
|
|
464
|
+
col = matchingJoin.label;
|
|
465
|
+
mainTableAlias = matchingJoin.alias as string;
|
|
466
|
+
}
|
|
467
|
+
const formatter = getEntityNameFormatter();
|
|
468
|
+
const tableAlias = mainTableAlias ? `${formatter(mainTableAlias)}.` : '';
|
|
469
|
+
if (!col) return '';
|
|
470
|
+
return tableAlias + formatter(col, filter.dataType?.[0]);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Get filter data type
|
|
475
|
+
*/
|
|
476
|
+
private getFilterDataType(filter: IGroupFilter): string {
|
|
477
|
+
const dataType = filter.dataType?.[0];
|
|
478
|
+
if (!dataType) return '';
|
|
479
|
+
return dataType;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Format value depending on datatype/db
|
|
484
|
+
*/
|
|
485
|
+
private formatValue(val: unknown, dt: string): string | null {
|
|
486
|
+
if (val === null || val === undefined) return null;
|
|
487
|
+
if (dt === 'date' || dt === 'datetime') {
|
|
488
|
+
return `'${val}'`;
|
|
489
|
+
}
|
|
490
|
+
switch (typeof val) {
|
|
491
|
+
case 'string':
|
|
492
|
+
return `'${val}'`;
|
|
493
|
+
case 'boolean':
|
|
494
|
+
return val ? '1' : '0';
|
|
495
|
+
default:
|
|
496
|
+
return String(val);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Format relative character filter
|
|
502
|
+
*/
|
|
503
|
+
private formatRelativeCharacterFilter(column: string, op: RangeOperator, value: any): string {
|
|
504
|
+
switch (op) {
|
|
505
|
+
case 'CONTAINS':
|
|
506
|
+
return `${column} LIKE '%${value}%'`;
|
|
507
|
+
case 'DOES_NOT_CONTAIN':
|
|
508
|
+
return `${column} NOT LIKE '%${value}%'`;
|
|
509
|
+
case 'STARTS_WITH':
|
|
510
|
+
return `${column} LIKE '${value}%'`;
|
|
511
|
+
case 'DOES_NOT_START_WITH':
|
|
512
|
+
return `${column} NOT LIKE '${value}%'`;
|
|
513
|
+
default:
|
|
514
|
+
throw new Error(`Unsupported character operator: ${op}`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Process search filter
|
|
520
|
+
*/
|
|
521
|
+
public processSearchFilter(filter: IGroupFilter, isSearch = true): string {
|
|
522
|
+
if (!filter.searchConfig) return '';
|
|
523
|
+
|
|
524
|
+
const { joinRelation = [] } = this.joinClauses || {};
|
|
525
|
+
const columnName = filter.columnNames?.[0] ?? filter.columnIds?.[0];
|
|
526
|
+
const joinTableDetails = joinRelation.find((join) => join.id === columnName);
|
|
527
|
+
const tableRef = joinTableDetails?.alias ?? joinTableDetails?.table;
|
|
528
|
+
const formatter = getEntityNameFormatter();
|
|
529
|
+
let column = this.getColumnName(filter);
|
|
530
|
+
if (joinTableDetails) {
|
|
531
|
+
column = `${formatter(tableRef!, filter.dataType?.[0])}.${formatter(joinTableDetails.label, filter.dataType?.[0])}`;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const castType = MAX_STRING_TYPE;
|
|
535
|
+
const { searchString, matchCase } = filter.searchConfig;
|
|
536
|
+
|
|
537
|
+
const columnExpr =
|
|
538
|
+
matchCase && isSearch
|
|
539
|
+
? `CAST(${column} AS ${castType})`
|
|
540
|
+
: `LOWER(CAST(${column} AS ${castType}))`;
|
|
541
|
+
if (!isSearch) {
|
|
542
|
+
// --- No search input mode ---
|
|
543
|
+
// This handles NULL or empty strings gracefully COALESCE support all databases
|
|
544
|
+
return `COALESCE(${columnExpr}, '')`;
|
|
545
|
+
}
|
|
546
|
+
// --- Normal search mode ---
|
|
547
|
+
const valueExpr = matchCase ? `'%${searchString}%'` : `'%${searchString.toLowerCase()}%'`;
|
|
548
|
+
return `${columnExpr} LIKE ${valueExpr}`;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private getManualFilterMatch(
|
|
552
|
+
value = '',
|
|
553
|
+
filter: IGroupFilter,
|
|
554
|
+
operator: RangeOperator,
|
|
555
|
+
manualConfig?: { column: string; options: IManualFilterOption[] },
|
|
556
|
+
): string {
|
|
557
|
+
if (
|
|
558
|
+
!manualConfig ||
|
|
559
|
+
!Array.isArray(manualConfig.options) ||
|
|
560
|
+
manualConfig.options.length === 0
|
|
561
|
+
) {
|
|
562
|
+
return '';
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const columnType = filter.dataType?.[0] || '';
|
|
566
|
+
const formattedColumn = this.getColumnName(filter);
|
|
567
|
+
|
|
568
|
+
const {
|
|
569
|
+
isBlankOperator,
|
|
570
|
+
isNotBlankOperator,
|
|
571
|
+
isNegativeOperator,
|
|
572
|
+
isStartsWithOperator,
|
|
573
|
+
isContainsOperator,
|
|
574
|
+
} = this.getOperatorFlags(operator);
|
|
575
|
+
|
|
576
|
+
if (isBlankOperator) {
|
|
577
|
+
return columnType !== EFilterDataType.STRING
|
|
578
|
+
? `${formattedColumn} IS NULL`
|
|
579
|
+
: `${formattedColumn} IS NULL OR ${formattedColumn} = ''`;
|
|
580
|
+
}
|
|
581
|
+
if (isNotBlankOperator) {
|
|
582
|
+
return columnType !== EFilterDataType.STRING
|
|
583
|
+
? `${formattedColumn} IS NOT NULL`
|
|
584
|
+
: `${formattedColumn} IS NOT NULL AND ${formattedColumn} <> ''`;
|
|
585
|
+
}
|
|
586
|
+
if (!value) return isNegativeOperator ? '1=1' : '1=0';
|
|
587
|
+
const matchedValues = manualConfig.options
|
|
588
|
+
.filter((opt) => {
|
|
589
|
+
const displayText = (opt.displayName || '').toString();
|
|
590
|
+
|
|
591
|
+
if (isContainsOperator) {
|
|
592
|
+
return displayText.includes(value);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (isStartsWithOperator) {
|
|
596
|
+
return displayText.startsWith(value);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return displayText.includes(value);
|
|
600
|
+
})
|
|
601
|
+
.map((opt) => this.formatValue(opt.id ?? opt.value, this.getFilterDataType(filter)));
|
|
602
|
+
|
|
603
|
+
if (matchedValues.length > 0) {
|
|
604
|
+
const sqlOperator = isNegativeOperator ? 'NOT IN' : 'IN';
|
|
605
|
+
return `${formattedColumn} ${sqlOperator} (${matchedValues.join(', ')})`;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return isNegativeOperator ? '1=1' : '1=0';
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
private getOperatorFlags(operator: RangeOperator) {
|
|
612
|
+
const isCharacterOperator = characterRangeFilterOperator.includes(operator);
|
|
613
|
+
const isBlankOperator = operator === 'IS_BLANK';
|
|
614
|
+
const isNotBlankOperator = operator === 'IS_NOT_BLANK';
|
|
615
|
+
const isNegativeOperator = negativeCharacterOperators.includes(operator);
|
|
616
|
+
const isStartsWithOperator = startsWithCharacterOperators.includes(operator);
|
|
617
|
+
const isContainsOperator = containsCharacterOperators.includes(operator);
|
|
618
|
+
|
|
619
|
+
return {
|
|
620
|
+
isCharacterOperator,
|
|
621
|
+
isBlankOperator,
|
|
622
|
+
isNotBlankOperator,
|
|
623
|
+
isNegativeOperator,
|
|
624
|
+
isStartsWithOperator,
|
|
625
|
+
isContainsOperator,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const RUNTIME_TABLE_NAME = '$RUNTIME_TABLE_NAME';
|
|
2
|
+
export const RUNTIME_FILTER_EXPR = '$RUNTIME_FILTER_EXPR';
|
|
3
|
+
export const RUNTIME_SORT_EXPR = '$RUNTIME_SORT_EXPR';
|
|
4
|
+
export const RUNTIME_PAGINATION_EXPR = '$RUNTIME_PAGINATION_EXPR';
|
|
5
|
+
export const RUNTIME_LOGGEDIN_EMAIL = '$RUNTIME_LOGGEDIN_EMAIL';
|
|
6
|
+
export const RUNTIME_LOGGEDIN_NAME = '$RUNTIME_LOGGEDIN_NAME';
|
|
7
|
+
export const RUNTIME_CURRENT_DATE = '$RUNTIME_CURRENT_DATE';
|
|
8
|
+
export const RUNTIME_CURRENT_DATETIME = '$RUNTIME_CURRENT_DATETIME';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Binary, ExpressionValue } from '../sql-types';
|
|
2
|
+
|
|
3
|
+
export function toBinaryExpression(
|
|
4
|
+
operator: string,
|
|
5
|
+
left: ExpressionValue,
|
|
6
|
+
right: ExpressionValue,
|
|
7
|
+
parentheses = false,
|
|
8
|
+
): Binary {
|
|
9
|
+
return {
|
|
10
|
+
type: 'binary_expr',
|
|
11
|
+
operator,
|
|
12
|
+
left,
|
|
13
|
+
right,
|
|
14
|
+
parentheses,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Binary, Case, ExpressionValue } from '../sql-types';
|
|
2
|
+
|
|
3
|
+
export function toCase(args: {
|
|
4
|
+
whenList: {
|
|
5
|
+
cond: Binary;
|
|
6
|
+
result: ExpressionValue;
|
|
7
|
+
type: 'when';
|
|
8
|
+
}[];
|
|
9
|
+
elseResult: { type: 'else'; result: ExpressionValue };
|
|
10
|
+
}): Case {
|
|
11
|
+
return {
|
|
12
|
+
type: 'case',
|
|
13
|
+
expr: null,
|
|
14
|
+
args: [...args.whenList, args.elseResult],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Column, ColumnRef, ExpressionValue } from '../sql-types';
|
|
2
|
+
|
|
3
|
+
export function toColumnRef(columName: string, table: string | null = null): ColumnRef {
|
|
4
|
+
return {
|
|
5
|
+
type: 'column_ref',
|
|
6
|
+
table: table,
|
|
7
|
+
column: columName,
|
|
8
|
+
collate: undefined,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function toColumn(expr: ExpressionValue, as: string | null = null): Column {
|
|
13
|
+
return {
|
|
14
|
+
type: 'column',
|
|
15
|
+
expr: expr,
|
|
16
|
+
as: as,
|
|
17
|
+
};
|
|
18
|
+
}
|