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.
Files changed (225) hide show
  1. package/.turbo/turbo-build.log +9 -0
  2. package/.turbo/turbo-check-types.log +4 -0
  3. package/.turbo/turbo-lint.log +126 -0
  4. package/README.md +45 -0
  5. package/coverage/base.css +224 -0
  6. package/coverage/block-navigation.js +87 -0
  7. package/coverage/favicon.png +0 -0
  8. package/coverage/index.html +236 -0
  9. package/coverage/prettify.css +1 -0
  10. package/coverage/prettify.js +2 -0
  11. package/coverage/sort-arrow-sprite.png +0 -0
  12. package/coverage/sorter.js +210 -0
  13. package/coverage/src/constants.ts.html +826 -0
  14. package/coverage/src/database_types.ts.html +136 -0
  15. package/coverage/src/epm-query-builder/EpmQueryBuilder.ts.html +166 -0
  16. package/coverage/src/epm-query-builder/base/BaseAdvancedAggregations.ts.html +568 -0
  17. package/coverage/src/epm-query-builder/base/BaseAnalyticalFunctions.ts.html +694 -0
  18. package/coverage/src/epm-query-builder/base/BaseCTEGenerator.ts.html +1459 -0
  19. package/coverage/src/epm-query-builder/base/BaseCountQueryBuilder.ts.html +400 -0
  20. package/coverage/src/epm-query-builder/base/BaseMeasureBuilder.ts.html +295 -0
  21. package/coverage/src/epm-query-builder/base/BaseOrderBuilder.ts.html +670 -0
  22. package/coverage/src/epm-query-builder/base/BasePaginationBuilder.ts.html +364 -0
  23. package/coverage/src/epm-query-builder/base/BaseQueryBuilder.ts.html +238 -0
  24. package/coverage/src/epm-query-builder/base/BaseRollupBuilder.ts.html +532 -0
  25. package/coverage/src/epm-query-builder/base/BaseSqlBuilder.ts.html +601 -0
  26. package/coverage/src/epm-query-builder/base/BaseSuperFilterBuilder.ts.html +1966 -0
  27. package/coverage/src/epm-query-builder/base/BaseUtilities.ts.html +1798 -0
  28. package/coverage/src/epm-query-builder/base/ColumnRefUtils.ts.html +211 -0
  29. package/coverage/src/epm-query-builder/base/RelationshipResolver.ts.html +706 -0
  30. package/coverage/src/epm-query-builder/base/SharedFilterBuilder.ts.html +1717 -0
  31. package/coverage/src/epm-query-builder/base/index.html +326 -0
  32. package/coverage/src/epm-query-builder/constants/Aggregations.ts.html +133 -0
  33. package/coverage/src/epm-query-builder/constants/Database.ts.html +103 -0
  34. package/coverage/src/epm-query-builder/constants/Source.ts.html +106 -0
  35. package/coverage/src/epm-query-builder/constants/index.html +146 -0
  36. package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbAdvancedAggregations.ts.html +286 -0
  37. package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbJoinBuilder.ts.html +280 -0
  38. package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbMeasureBuilder.ts.html +1924 -0
  39. package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbOrderBuilder.ts.html +769 -0
  40. package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbPaginationBuilder.ts.html +643 -0
  41. package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbQueryBuilder.ts.html +2644 -0
  42. package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbRollupBuilder.ts.html +478 -0
  43. package/coverage/src/epm-query-builder/dialects/duckdb/DuckDbSuperFilterBuilder.ts.html +1195 -0
  44. package/coverage/src/epm-query-builder/dialects/duckdb/index.html +221 -0
  45. package/coverage/src/epm-query-builder/errors/QueryBuilderErrors.ts.html +280 -0
  46. package/coverage/src/epm-query-builder/errors/index.html +116 -0
  47. package/coverage/src/epm-query-builder/index.html +116 -0
  48. package/coverage/src/epm-query-builder/interfaces/IDatabaseQueryBuilder.ts.html +100 -0
  49. package/coverage/src/epm-query-builder/interfaces/index.html +131 -0
  50. package/coverage/src/epm-query-builder/interfaces/index.ts.html +88 -0
  51. package/coverage/src/epm-query-builder/utils/format.ts.html +151 -0
  52. package/coverage/src/epm-query-builder/utils/index.html +146 -0
  53. package/coverage/src/epm-query-builder/utils/sql.ts.html +247 -0
  54. package/coverage/src/epm-query-builder/utils/validation.ts.html +124 -0
  55. package/coverage/src/epm-query-builder/validation/QueryOptionsValidator.ts.html +631 -0
  56. package/coverage/src/epm-query-builder/validation/SqlQueryValidator.ts.html +475 -0
  57. package/coverage/src/epm-query-builder/validation/index.html +131 -0
  58. package/coverage/src/filters/FilterConditionBuilder.ts.html +427 -0
  59. package/coverage/src/filters/filter-types.ts.html +484 -0
  60. package/coverage/src/filters/index.html +131 -0
  61. package/coverage/src/index.html +176 -0
  62. package/coverage/src/index.ts.html +103 -0
  63. package/coverage/src/js-lib/JsToSqlParser.ts.html +736 -0
  64. package/coverage/src/js-lib/ParseContext.ts.html +532 -0
  65. package/coverage/src/js-lib/db/azuresql/AzureSqlCallExpressionVisitor.ts.html +196 -0
  66. package/coverage/src/js-lib/db/azuresql/index.html +116 -0
  67. package/coverage/src/js-lib/db/base/ArrayExpressionVisitor.ts.html +133 -0
  68. package/coverage/src/js-lib/db/base/AssignmentExpressionVisitor.ts.html +187 -0
  69. package/coverage/src/js-lib/db/base/BinaryExpressionVisitor.ts.html +223 -0
  70. package/coverage/src/js-lib/db/base/CallExpressionVisitor.ts.html +5479 -0
  71. package/coverage/src/js-lib/db/base/IdentifierVisitor.ts.html +283 -0
  72. package/coverage/src/js-lib/db/base/LiteralVisitor.ts.html +199 -0
  73. package/coverage/src/js-lib/db/base/MemberExpressionVisitor.ts.html +193 -0
  74. package/coverage/src/js-lib/db/base/ProgramVisitor.ts.html +139 -0
  75. package/coverage/src/js-lib/db/base/UnaryExpressionVisitor.ts.html +181 -0
  76. package/coverage/src/js-lib/db/base/VisitorInterface.ts.html +103 -0
  77. package/coverage/src/js-lib/db/base/index.html +251 -0
  78. package/coverage/src/js-lib/db/bigquery/BigQueryCallExpressionVisitor.ts.html +1747 -0
  79. package/coverage/src/js-lib/db/bigquery/index.html +116 -0
  80. package/coverage/src/js-lib/db/commonTransforms.ts.html +2074 -0
  81. package/coverage/src/js-lib/db/databricks/DatabricksCallExpressionVisitor.ts.html +1303 -0
  82. package/coverage/src/js-lib/db/databricks/index.html +116 -0
  83. package/coverage/src/js-lib/db/fabricsql/FabricSqlCallExpressionVisitor.ts.html +196 -0
  84. package/coverage/src/js-lib/db/fabricsql/index.html +116 -0
  85. package/coverage/src/js-lib/db/fabricwarehouse/FabricWarehouseCallExpressionVisitor.ts.html +292 -0
  86. package/coverage/src/js-lib/db/fabricwarehouse/index.html +116 -0
  87. package/coverage/src/js-lib/db/index.html +116 -0
  88. package/coverage/src/js-lib/db/postgresql/PostgreSqlCallExpressionVisitor.ts.html +985 -0
  89. package/coverage/src/js-lib/db/postgresql/index.html +116 -0
  90. package/coverage/src/js-lib/db/redshift/RedshiftCallExpressionVisitor.ts.html +685 -0
  91. package/coverage/src/js-lib/db/redshift/index.html +116 -0
  92. package/coverage/src/js-lib/db/sample/SampleCallExpressionVisitor.ts.html +196 -0
  93. package/coverage/src/js-lib/db/sample/index.html +116 -0
  94. package/coverage/src/js-lib/db/snowflake/SnowflakeCallExpressionVisitor.ts.html +1447 -0
  95. package/coverage/src/js-lib/db/snowflake/index.html +116 -0
  96. package/coverage/src/js-lib/db/validator/FormulaValidator.ts.html +4162 -0
  97. package/coverage/src/js-lib/db/validator/index.html +116 -0
  98. package/coverage/src/js-lib/index.html +131 -0
  99. package/coverage/src/js-lib/objects/BaseObject.ts.html +169 -0
  100. package/coverage/src/js-lib/objects/DateObject.ts.html +169 -0
  101. package/coverage/src/js-lib/objects/PctObject.ts.html +178 -0
  102. package/coverage/src/js-lib/objects/index.html +146 -0
  103. package/coverage/src/query-builder/PaginationBuilder.ts.html +142 -0
  104. package/coverage/src/query-builder/QueryBuilder.ts.html +3118 -0
  105. package/coverage/src/query-builder/SuperFilterBuilder.ts.html +1969 -0
  106. package/coverage/src/query-builder/index.html +146 -0
  107. package/coverage/src/runtime_var.ts.html +109 -0
  108. package/coverage/src/sql-lib/binary_expr.ts.html +133 -0
  109. package/coverage/src/sql-lib/case.ts.html +133 -0
  110. package/coverage/src/sql-lib/column.ts.html +139 -0
  111. package/coverage/src/sql-lib/else.ts.html +124 -0
  112. package/coverage/src/sql-lib/function.ts.html +112 -0
  113. package/coverage/src/sql-lib/index.html +251 -0
  114. package/coverage/src/sql-lib/join.ts.html +127 -0
  115. package/coverage/src/sql-lib/literal.ts.html +130 -0
  116. package/coverage/src/sql-lib/select.ts.html +547 -0
  117. package/coverage/src/sql-lib/unary_expr.ts.html +112 -0
  118. package/coverage/src/sql-lib/when.ts.html +130 -0
  119. package/coverage/src/sql_query_gen.ts.html +535 -0
  120. package/coverage/src/superFilter/DateFilterFactory.ts.html +625 -0
  121. package/coverage/src/superFilter/dateFunction.ts.html +193 -0
  122. package/coverage/src/superFilter/index.html +131 -0
  123. package/coverage/src/utils.ts.html +571 -0
  124. package/dist/index.cjs +8440 -0
  125. package/dist/index.d.cts +927 -0
  126. package/dist/index.d.cts.map +1 -0
  127. package/dist/index.d.ts +927 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +8387 -0
  130. package/dist/index.js.map +1 -0
  131. package/eslint.config.js +4 -0
  132. package/jest.config.ts +44 -0
  133. package/package.json +45 -0
  134. package/src/constants.ts +247 -0
  135. package/src/epm-query-builder/EpmQueryBuilder.ts +27 -0
  136. package/src/epm-query-builder/base/BaseAdvancedAggregations.ts +161 -0
  137. package/src/epm-query-builder/base/BaseAnalyticalFunctions.ts +203 -0
  138. package/src/epm-query-builder/base/BaseCTEGenerator.ts +458 -0
  139. package/src/epm-query-builder/base/BaseCountQueryBuilder.ts +105 -0
  140. package/src/epm-query-builder/base/BaseMeasureBuilder.ts +87 -0
  141. package/src/epm-query-builder/base/BaseOrderBuilder.ts +195 -0
  142. package/src/epm-query-builder/base/BasePaginationBuilder.ts +93 -0
  143. package/src/epm-query-builder/base/BaseQueryBuilder.ts +51 -0
  144. package/src/epm-query-builder/base/BaseRollupBuilder.ts +149 -0
  145. package/src/epm-query-builder/base/BaseSqlBuilder.ts +172 -0
  146. package/src/epm-query-builder/base/BaseSuperFilterBuilder.ts +627 -0
  147. package/src/epm-query-builder/base/BaseUtilities.ts +571 -0
  148. package/src/epm-query-builder/base/ColumnRefUtils.ts +42 -0
  149. package/src/epm-query-builder/base/RelationshipResolver.ts +207 -0
  150. package/src/epm-query-builder/base/SharedFilterBuilder.ts +544 -0
  151. package/src/epm-query-builder/constants/Aggregations.ts +16 -0
  152. package/src/epm-query-builder/constants/Database.ts +6 -0
  153. package/src/epm-query-builder/constants/Source.ts +7 -0
  154. package/src/epm-query-builder/dialects/duckdb/DuckDbAdvancedAggregations.ts +67 -0
  155. package/src/epm-query-builder/dialects/duckdb/DuckDbJoinBuilder.ts +65 -0
  156. package/src/epm-query-builder/dialects/duckdb/DuckDbMeasureBuilder.ts +626 -0
  157. package/src/epm-query-builder/dialects/duckdb/DuckDbOrderBuilder.ts +228 -0
  158. package/src/epm-query-builder/dialects/duckdb/DuckDbPaginationBuilder.ts +186 -0
  159. package/src/epm-query-builder/dialects/duckdb/DuckDbQueryBuilder.ts +853 -0
  160. package/src/epm-query-builder/dialects/duckdb/DuckDbRollupBuilder.ts +131 -0
  161. package/src/epm-query-builder/dialects/duckdb/DuckDbSuperFilterBuilder.ts +370 -0
  162. package/src/epm-query-builder/errors/QueryBuilderErrors.ts +65 -0
  163. package/src/epm-query-builder/interfaces/IDatabaseQueryBuilder.ts +5 -0
  164. package/src/epm-query-builder/interfaces/index.ts +1 -0
  165. package/src/epm-query-builder/types/query-builder-types.d.ts +289 -0
  166. package/src/epm-query-builder/utils/format.ts +22 -0
  167. package/src/epm-query-builder/utils/sql.ts +54 -0
  168. package/src/epm-query-builder/utils/validation.ts +13 -0
  169. package/src/epm-query-builder/validation/QueryOptionsValidator.ts +182 -0
  170. package/src/epm-query-builder/validation/SqlQueryValidator.ts +130 -0
  171. package/src/filters/FilterConditionBuilder.ts +114 -0
  172. package/src/filters/filter-types.ts +133 -0
  173. package/src/index.ts +10 -0
  174. package/src/js-lib/JsToSqlParser.ts +217 -0
  175. package/src/js-lib/ParseContext.ts +149 -0
  176. package/src/js-lib/db/base/ArrayExpressionVisitor.ts +16 -0
  177. package/src/js-lib/db/base/AssignmentExpressionVisitor.ts +34 -0
  178. package/src/js-lib/db/base/BinaryExpressionVisitor.ts +46 -0
  179. package/src/js-lib/db/base/CallExpressionVisitor.ts +1798 -0
  180. package/src/js-lib/db/base/IdentifierVisitor.ts +66 -0
  181. package/src/js-lib/db/base/LiteralVisitor.ts +38 -0
  182. package/src/js-lib/db/base/MemberExpressionVisitor.ts +36 -0
  183. package/src/js-lib/db/base/ProgramVisitor.ts +18 -0
  184. package/src/js-lib/db/base/UnaryExpressionVisitor.ts +32 -0
  185. package/src/js-lib/db/base/VisitorInterface.ts +6 -0
  186. package/src/js-lib/db/validator/FormulaValidator.ts +1235 -0
  187. package/src/js-lib/objects/BaseObject.ts +28 -0
  188. package/src/js-lib/objects/DateObject.ts +28 -0
  189. package/src/js-lib/objects/PctObject.ts +31 -0
  190. package/src/query-builder/PaginationBuilder.ts +19 -0
  191. package/src/query-builder/QueryBuilder.ts +1035 -0
  192. package/src/query-builder/SuperFilterBuilder.ts +628 -0
  193. package/src/runtime_var.ts +8 -0
  194. package/src/sql-lib/binary_expr.ts +16 -0
  195. package/src/sql-lib/case.ts +16 -0
  196. package/src/sql-lib/column.ts +18 -0
  197. package/src/sql-lib/else.ts +13 -0
  198. package/src/sql-lib/function.ts +9 -0
  199. package/src/sql-lib/join.ts +14 -0
  200. package/src/sql-lib/literal.ts +15 -0
  201. package/src/sql-lib/select.ts +154 -0
  202. package/src/sql-lib/unary_expr.ts +9 -0
  203. package/src/sql-lib/when.ts +15 -0
  204. package/src/sql-types.d.ts +565 -0
  205. package/src/sql_query_gen.ts +150 -0
  206. package/src/superFilter/DateFilterFactory.ts +180 -0
  207. package/src/superFilter/dateFunction.ts +36 -0
  208. package/src/utils.ts +354 -0
  209. package/test-output/report/junit.xml +329 -0
  210. package/tests/JsToSqlParser.test.ts +163 -0
  211. package/tests/QueryBuilder.test.ts +1320 -0
  212. package/tests/js-lib/CallExpressionVisitor.test.ts +820 -0
  213. package/tests/mocks/MockQueryResolver.ts +14 -0
  214. package/tests/sanity.test.ts +146 -0
  215. package/tests/sql-lib/binary_expr.test.ts +75 -0
  216. package/tests/sql-lib/case.test.ts +117 -0
  217. package/tests/sql-lib/column.test.ts +87 -0
  218. package/tests/sql-lib/else.test.ts +56 -0
  219. package/tests/sql-lib/function.test.ts +96 -0
  220. package/tests/sql-lib/literal.test.ts +75 -0
  221. package/tests/sql-lib/select.test.ts +245 -0
  222. package/tests/sql-lib/unary_expr.test.ts +32 -0
  223. package/tests/utils.test.ts +13 -0
  224. package/tsconfig.json +24 -0
  225. package/tsdown.config.ts +23 -0
@@ -0,0 +1,627 @@
1
+ import {
2
+ FilterConfig,
3
+ SuperFilterConfig,
4
+ SuperFilterChild,
5
+ MeasureFilterConfig,
6
+ RangeFilter,
7
+ EpmQueryBuilderOptions,
8
+ } from '@epm-query-builder/types/query-builder-types';
9
+ import { SharedFilterBuilder } from '@epm-query-builder/base/SharedFilterBuilder';
10
+ import { BaseUtilities } from '@epm-query-builder/base/BaseUtilities';
11
+ import { FilterValidationError } from '@epm-query-builder/errors/QueryBuilderErrors';
12
+
13
+ export class BaseSuperFilterBuilder {
14
+ protected options: EpmQueryBuilderOptions;
15
+
16
+ constructor(options: EpmQueryBuilderOptions) {
17
+ this.options = options;
18
+ }
19
+
20
+ buildWhereClause(): string {
21
+ if (!this.options.superFilters) {
22
+ return '';
23
+ }
24
+
25
+ return this.buildNestedFilterGroups(this.options.superFilters);
26
+ }
27
+
28
+ protected buildNestedFilterGroups(superFilters: SuperFilterConfig): string {
29
+ if (!superFilters.children?.length) {
30
+ return '';
31
+ }
32
+
33
+ const childConditions = superFilters.children
34
+ .map((child) => this.buildSuperFilterChild(child))
35
+ .filter((condition) => condition);
36
+
37
+ if (childConditions.length === 0) {
38
+ return '';
39
+ }
40
+
41
+ const operator = superFilters.condition?.toUpperCase() === 'OR' ? ' OR ' : ' AND ';
42
+ return childConditions.length === 1
43
+ ? childConditions[0]
44
+ : `(${childConditions.join(operator)})`;
45
+ }
46
+
47
+ protected buildSuperFilterChild(child: SuperFilterChild): string {
48
+ if (child.isGroup && child.children) {
49
+ const nestedGroup: SuperFilterConfig = {
50
+ groupId: child.groupId || 'nested',
51
+ groupLabel: child.groupLabel || 'nested',
52
+ condition: child.condition || 'AND',
53
+ children: child.children,
54
+ };
55
+ return this.buildNestedFilterGroups(nestedGroup);
56
+ } else if (child.isFilter && child.filters) {
57
+ return this.buildFilterCondition(child.filters);
58
+ } else if (child.filters) {
59
+ return this.buildFilterCondition(child.filters);
60
+ }
61
+ return '';
62
+ }
63
+
64
+ protected buildFilterCondition(filter: FilterConfig): string {
65
+ if (!filter) return '';
66
+
67
+ if (filter.filterType?.toUpperCase() === 'MEASURE') {
68
+ return this.buildMeasureFilter();
69
+ }
70
+
71
+ if (
72
+ filter.filterType?.toUpperCase() === 'RANGE' &&
73
+ Array.isArray(filter.aggregationType) &&
74
+ filter.aggregationType.length > 0
75
+ ) {
76
+ return '';
77
+ }
78
+ return SharedFilterBuilder.buildFilterCondition(filter);
79
+ }
80
+
81
+ protected buildValuesFilter(filter: FilterConfig): string {
82
+ if (filter.isCrossHighlight === true) {
83
+ return this.buildCrossHighlightFilter(filter);
84
+ }
85
+ return SharedFilterBuilder.buildValuesFilter(filter);
86
+ }
87
+
88
+ protected buildRangeFilter(filter: FilterConfig): string {
89
+ return SharedFilterBuilder.buildRangeFilter(filter);
90
+ }
91
+
92
+ protected buildDateFilter(filter: FilterConfig): string {
93
+ if (!filter.columnNames?.length || !filter.dateRangeFilter?.length) {
94
+ return '';
95
+ }
96
+
97
+ const column = filter.columnNames[0];
98
+ const dateRange = filter.dateRangeFilter[0];
99
+
100
+ const startDate = BaseUtilities.formatValue(dateRange.startDate);
101
+ const endDate = BaseUtilities.formatValue(dateRange.endDate);
102
+
103
+ return `${column} BETWEEN ${startDate} AND ${endDate}`;
104
+ }
105
+
106
+ protected buildMeasureFilter(): string {
107
+ const measureFilters = this.extractMeasureFilters();
108
+ if (measureFilters.length === 0) {
109
+ return '';
110
+ }
111
+
112
+ const conditions = measureFilters.map((filter) => this.buildMeasureCondition(filter));
113
+ return BaseUtilities.combineConditions(
114
+ conditions.filter((c) => c),
115
+ 'AND',
116
+ );
117
+ }
118
+
119
+ protected extractMeasureFilters(): MeasureFilterConfig[] {
120
+ if (!this.options.superFilters?.children) {
121
+ return [];
122
+ }
123
+
124
+ const measureFilters: MeasureFilterConfig[] = [];
125
+
126
+ this.extractMeasureFiltersRecursively(this.options.superFilters.children, measureFilters);
127
+ return measureFilters;
128
+ }
129
+
130
+ private extractMeasureFiltersRecursively(
131
+ children: SuperFilterChild[],
132
+ measureFilters: MeasureFilterConfig[],
133
+ ): void {
134
+ children.forEach((child) => {
135
+ if (child.filters) {
136
+ const filter = child.filters;
137
+ const isMeasureFilterType = filter.filterType === 'MEASURE';
138
+ const isRangeWithAggregation =
139
+ filter.filterType === 'RANGE' &&
140
+ Array.isArray(filter.aggregationType) &&
141
+ filter.aggregationType.length > 0;
142
+
143
+ if (isMeasureFilterType || isRangeWithAggregation) {
144
+ if (filter.rangeFilter?.length) {
145
+ filter.rangeFilter.forEach((range: RangeFilter) => {
146
+ const hasFrom =
147
+ range.from !== undefined && range.from !== null && range.fromCondition;
148
+ const hasTo = range.to !== undefined && range.to !== null && range.toCondition;
149
+ const hasLegacyOperator =
150
+ range.operator &&
151
+ range.value !== undefined &&
152
+ range.value !== null &&
153
+ !hasFrom &&
154
+ !hasTo;
155
+
156
+ if (hasFrom) {
157
+ measureFilters.push({
158
+ id: `${filter.tableNames?.[0]}.${filter.columnNames?.[0]}`,
159
+ columnName: filter.columnNames?.[0] || '',
160
+ tableName: filter.tableNames?.[0] || '',
161
+ aggregationType: filter.aggregationType?.[0],
162
+ operator: this.normalizeRangeOperator(range.fromCondition),
163
+ value: range.from,
164
+ dataType: filter.dataType?.[0] || 'string',
165
+ logicalOperator:
166
+ hasTo && range.logicalOperator
167
+ ? range.logicalOperator
168
+ : filter.logicalOperator || 'AND',
169
+ });
170
+ }
171
+
172
+ if (hasTo) {
173
+ measureFilters.push({
174
+ id: `${filter.tableNames?.[0]}.${filter.columnNames?.[0]}`,
175
+ columnName: filter.columnNames?.[0] || '',
176
+ tableName: filter.tableNames?.[0] || '',
177
+ aggregationType: filter.aggregationType?.[0],
178
+ operator: this.normalizeRangeOperator(range.toCondition),
179
+ value: range.to,
180
+ dataType: filter.dataType?.[0] || 'string',
181
+ logicalOperator:
182
+ hasFrom && range.logicalOperator
183
+ ? range.logicalOperator
184
+ : filter.logicalOperator || 'AND',
185
+ });
186
+ }
187
+
188
+ if (hasLegacyOperator) {
189
+ measureFilters.push({
190
+ id: `${filter.tableNames?.[0]}.${filter.columnNames?.[0]}`,
191
+ columnName: filter.columnNames?.[0] || '',
192
+ tableName: filter.tableNames?.[0] || '',
193
+ aggregationType: filter.aggregationType?.[0],
194
+ operator: this.normalizeRangeOperator(range.operator),
195
+ value: range.value,
196
+ dataType: filter.dataType?.[0] || 'string',
197
+ logicalOperator: filter.logicalOperator || 'AND',
198
+ });
199
+ }
200
+ });
201
+ }
202
+ }
203
+ }
204
+
205
+ if (child.children) {
206
+ this.extractMeasureFiltersRecursively(child.children, measureFilters);
207
+ }
208
+ });
209
+ }
210
+
211
+ private normalizeRangeOperator(operator: string): string {
212
+ if (!operator) return 'IS_EQUAL_TO';
213
+
214
+ const normalized = operator.toUpperCase().trim();
215
+
216
+ switch (normalized) {
217
+ case 'IS':
218
+ case 'EQUALS':
219
+ return 'IS_EQUAL_TO';
220
+ case 'IS_NOT':
221
+ case 'NOT_EQUALS':
222
+ return 'IS_NOT_EQUAL_TO';
223
+ case 'IS_GREATER_THAN':
224
+ return 'IS_GREATER_THAN';
225
+ case 'IS_GREATER_THAN_OR_EQUAL_TO':
226
+ case 'IS_ON_OR_AFTER':
227
+ return 'IS_GREATER_THAN_OR_EQUAL_TO';
228
+ case 'IS_LESS_THAN':
229
+ case 'IS_BEFORE':
230
+ return 'IS_LESS_THAN';
231
+ case 'IS_LESS_THAN_OR_EQUAL_TO':
232
+ case 'IS_ON_OR_BEFORE':
233
+ return 'IS_LESS_THAN_OR_EQUAL_TO';
234
+ case 'IS_BLANK':
235
+ return 'IS_BLANK';
236
+ case 'IS_NOT_BLANK':
237
+ return 'IS_NOT_BLANK';
238
+ default:
239
+ return normalized.includes('_') ? normalized : 'IS_EQUAL_TO';
240
+ }
241
+ }
242
+
243
+ protected buildMeasureCondition(filter: MeasureFilterConfig): string {
244
+ const measureExpr = filter.aggregationType
245
+ ? `${filter.aggregationType.toUpperCase()}("${filter.tableName}"."${filter.columnName}")`
246
+ : `"${filter.tableName}"."${filter.columnName}"`;
247
+
248
+ const value = filter.dataType === 'string' ? `'${filter.value}'` : filter.value;
249
+
250
+ switch (filter.operator.toUpperCase()) {
251
+ case 'IS':
252
+ case 'IS_EQUAL_TO':
253
+ return `${measureExpr} = ${value}`;
254
+ case 'IS_NOT':
255
+ case 'IS_NOT_EQUAL_TO':
256
+ return `${measureExpr} != ${value}`;
257
+ case 'IS_GREATER_THAN':
258
+ return `${measureExpr} > ${value}`;
259
+ case 'IS_GREATER_THAN_OR_EQUAL_TO':
260
+ return `${measureExpr} >= ${value}`;
261
+ case 'IS_LESS_THAN':
262
+ return `${measureExpr} < ${value}`;
263
+ case 'IS_LESS_THAN_OR_EQUAL_TO':
264
+ return `${measureExpr} <= ${value}`;
265
+ case 'IS_BLANK':
266
+ return `${measureExpr} IS NULL`;
267
+ case 'IS_NOT_BLANK':
268
+ return `${measureExpr} IS NOT NULL`;
269
+ default:
270
+ return `${measureExpr} = ${value}`;
271
+ }
272
+ }
273
+
274
+ protected buildTupleFilter(filter: FilterConfig): string {
275
+ if (!filter.columnNames?.length || !filter.valuesFilter?.length) {
276
+ return '';
277
+ }
278
+
279
+ const columns = filter.columnNames;
280
+ const tupleConditions: string[] = [];
281
+
282
+ filter.valuesFilter.forEach((valueItem) => {
283
+ if (Array.isArray(valueItem.id)) {
284
+ const tupleValues = valueItem.id
285
+ .map((id, index) => `${columns[index]} = ${BaseUtilities.formatValue(id.toString())}`)
286
+ .join(' AND ');
287
+ tupleConditions.push(`(${tupleValues})`);
288
+ }
289
+ });
290
+
291
+ const operator = filter.valuesFilterApplicationType === 'INCLUDE' ? 'OR' : 'AND NOT';
292
+ const result =
293
+ tupleConditions.length > 0
294
+ ? tupleConditions.length === 1
295
+ ? tupleConditions[0]
296
+ : `(${tupleConditions.join(` ${operator} `)})`
297
+ : '';
298
+
299
+ return filter.isCrossHighlight === true ? this.wrapWithCrossHighlight(result) : result;
300
+ }
301
+
302
+ protected buildSearchFilter(filter: FilterConfig): string {
303
+ return SharedFilterBuilder.buildSearchFilter(filter);
304
+ }
305
+
306
+ protected buildRankingFilter(filter: FilterConfig): string {
307
+ return SharedFilterBuilder.buildRankingFilter(filter);
308
+ }
309
+
310
+ protected buildBlankFilter(filter: FilterConfig): string {
311
+ if (!filter.columnNames?.length || !filter.blankFilterConfig) {
312
+ return '';
313
+ }
314
+
315
+ const column = filter.columnNames[0];
316
+ const blankConfig = filter.blankFilterConfig;
317
+
318
+ if (blankConfig.operator === 'IS_BLANK') {
319
+ if (blankConfig.treatEmptyStringAsBlank) {
320
+ return `(${column} IS NULL OR TRIM(${column}) = '')`;
321
+ } else {
322
+ return `${column} IS NULL`;
323
+ }
324
+ } else {
325
+ if (blankConfig.treatEmptyStringAsBlank) {
326
+ return `(${column} IS NOT NULL AND TRIM(${column}) != '')`;
327
+ } else {
328
+ return `${column} IS NOT NULL`;
329
+ }
330
+ }
331
+ }
332
+
333
+ protected buildRelativePeriodFilter(filter: FilterConfig): string {
334
+ if (!filter.columnNames?.length || !filter.relativePeriodFilter) {
335
+ return '';
336
+ }
337
+
338
+ const tableName =
339
+ filter.tableNames?.[0] || BaseUtilities.getDefaultTableNameFromOptions(this.options);
340
+ const column = BaseUtilities.buildColumnReference(tableName, filter.columnNames[0]);
341
+ return this.buildRelativePeriodCondition(column, filter.relativePeriodFilter);
342
+ }
343
+
344
+ protected buildDateHierarchyFilter(filter: FilterConfig): string {
345
+ if (!filter.columnNames?.length || !filter.dateHierarchyConfig) {
346
+ return '';
347
+ }
348
+
349
+ const tableName =
350
+ filter.tableNames?.[0] || BaseUtilities.getDefaultTableNameFromOptions(this.options);
351
+ const column = BaseUtilities.buildColumnReference(tableName, filter.columnNames[0]);
352
+ const hierarchyConfig = filter.dateHierarchyConfig;
353
+
354
+ if (!hierarchyConfig.level) {
355
+ return `${column} IS NOT NULL`;
356
+ }
357
+
358
+ if (!hierarchyConfig.values?.length) {
359
+ let hierarchyFunction: string;
360
+ switch (hierarchyConfig.level) {
361
+ case 'YEAR':
362
+ hierarchyFunction = `EXTRACT(YEAR FROM ${column})`;
363
+ break;
364
+ case 'QUARTER':
365
+ hierarchyFunction = `EXTRACT(QUARTER FROM ${column})`;
366
+ break;
367
+ case 'MONTH':
368
+ hierarchyFunction = `EXTRACT(MONTH FROM ${column})`;
369
+ break;
370
+ case 'DAY':
371
+ hierarchyFunction = `EXTRACT(DAY FROM ${column})`;
372
+ break;
373
+ case 'WEEK':
374
+ hierarchyFunction = `EXTRACT(WEEK FROM ${column})`;
375
+ break;
376
+ case 'DAYOFWEEK':
377
+ hierarchyFunction = `EXTRACT(DAYOFWEEK FROM ${column})`;
378
+ break;
379
+ default:
380
+ return `${column} IS NOT NULL`;
381
+ }
382
+ return `${hierarchyFunction} IS NOT NULL`;
383
+ }
384
+
385
+ let hierarchyFunction: string;
386
+ switch (hierarchyConfig.level) {
387
+ case 'YEAR':
388
+ hierarchyFunction = `EXTRACT(YEAR FROM ${column})`;
389
+ break;
390
+ case 'QUARTER':
391
+ hierarchyFunction = `EXTRACT(QUARTER FROM ${column})`;
392
+ break;
393
+ case 'MONTH':
394
+ hierarchyFunction = `EXTRACT(MONTH FROM ${column})`;
395
+ break;
396
+ case 'DAY':
397
+ hierarchyFunction = `EXTRACT(DAY FROM ${column})`;
398
+ break;
399
+ case 'WEEK':
400
+ hierarchyFunction = `EXTRACT(WEEK FROM ${column})`;
401
+ break;
402
+ case 'DAYOFWEEK':
403
+ hierarchyFunction = `EXTRACT(DAYOFWEEK FROM ${column})`;
404
+ break;
405
+ default:
406
+ throw new FilterValidationError(
407
+ 'DATE_HIERARCHY',
408
+ `unsupported level: ${hierarchyConfig.level}`,
409
+ {
410
+ level: hierarchyConfig.level,
411
+ supportedLevels: ['YEAR', 'QUARTER', 'MONTH', 'DAY', 'WEEK', 'DAYOFWEEK'],
412
+ },
413
+ );
414
+ }
415
+
416
+ if (hierarchyConfig.values.length === 1) {
417
+ return `${hierarchyFunction} = ${hierarchyConfig.values[0]}`;
418
+ } else {
419
+ const valuesList = hierarchyConfig.values.join(', ');
420
+ return `${hierarchyFunction} IN (${valuesList})`;
421
+ }
422
+ }
423
+
424
+ protected buildFieldParameterFilter(filter: FilterConfig): string {
425
+ if (!filter.fieldParameterMapping) {
426
+ return '';
427
+ }
428
+
429
+ const mapping = filter.fieldParameterMapping;
430
+ if (!mapping.targetField) {
431
+ return '';
432
+ }
433
+
434
+ const tableName =
435
+ mapping.targetTable || BaseUtilities.getDefaultTableNameFromOptions(this.options);
436
+ const column = BaseUtilities.buildColumnReference(tableName, mapping.targetField);
437
+
438
+ if (mapping.filterValues?.length) {
439
+ if (mapping.filterValues.length === 1) {
440
+ return `${column} = '${mapping.filterValues[0]}'`;
441
+ } else {
442
+ const valuesList = mapping.filterValues.map((v) => `'${v}'`).join(', ');
443
+ return `${column} IN (${valuesList})`;
444
+ }
445
+ }
446
+
447
+ return `${column} IS NOT NULL`;
448
+ }
449
+
450
+ protected buildRelativePeriodCondition(
451
+ column: string,
452
+ config: { duration: number; period: string; relativeDateFilter: string },
453
+ ): string {
454
+ const now = 'CURRENT_DATE';
455
+ const duration = config.duration;
456
+ const period = config.period;
457
+
458
+ switch (config.relativeDateFilter) {
459
+ case 'IS_IN_THE_LAST':
460
+ switch (period) {
461
+ case 'DAYS':
462
+ return `${column} >= ${now} - INTERVAL '${duration} days'`;
463
+ case 'WEEKS':
464
+ return `${column} >= ${now} - INTERVAL '${duration} weeks'`;
465
+ case 'MONTHS':
466
+ return `${column} >= ${now} - INTERVAL '${duration} months'`;
467
+ case 'YEARS':
468
+ return `${column} >= ${now} - INTERVAL '${duration} years'`;
469
+ default:
470
+ return `${column} >= ${now} - INTERVAL '${duration} days'`;
471
+ }
472
+ case 'IS_IN_THE_NEXT':
473
+ switch (period) {
474
+ case 'DAYS':
475
+ return `${column} <= ${now} + INTERVAL '${duration} days'`;
476
+ case 'WEEKS':
477
+ return `${column} <= ${now} + INTERVAL '${duration} weeks'`;
478
+ case 'MONTHS':
479
+ return `${column} <= ${now} + INTERVAL '${duration} months'`;
480
+ case 'YEARS':
481
+ return `${column} <= ${now} + INTERVAL '${duration} years'`;
482
+ default:
483
+ return `${column} <= ${now} + INTERVAL '${duration} days'`;
484
+ }
485
+ case 'IS_IN_THIS':
486
+ switch (period) {
487
+ case 'DAYS':
488
+ return `DATE_TRUNC('day', ${column}) = DATE_TRUNC('day', ${now})`;
489
+ case 'WEEKS':
490
+ return `DATE_TRUNC('week', ${column}) = DATE_TRUNC('week', ${now})`;
491
+ case 'MONTHS':
492
+ return `DATE_TRUNC('month', ${column}) = DATE_TRUNC('month', ${now})`;
493
+ case 'YEARS':
494
+ return `DATE_TRUNC('year', ${column}) = DATE_TRUNC('year', ${now})`;
495
+ default:
496
+ return `DATE_TRUNC('day', ${column}) = DATE_TRUNC('day', ${now})`;
497
+ }
498
+ default:
499
+ return `${column} = ${now}`;
500
+ }
501
+ }
502
+
503
+ private wrapWithCrossHighlight(condition: string): string {
504
+ return condition;
505
+ }
506
+
507
+ private buildCrossHighlightFilter(filter: FilterConfig): string {
508
+ if (!filter.columnNames?.length || !filter.valuesFilter?.length) {
509
+ return '';
510
+ }
511
+
512
+ const column = filter.columnNames[0];
513
+ const values = filter.valuesFilter
514
+ .flatMap((vf) => (Array.isArray(vf.id) ? vf.id : [vf.id]))
515
+ .filter((v) => v !== undefined);
516
+ const valueList = values.map((v) => BaseUtilities.formatValue(v.toString())).join(',');
517
+
518
+ return `${column} IN (${valueList})`;
519
+ }
520
+
521
+ protected calculateTopNValue(value: number, totalCount: number, isPercentage: boolean): number {
522
+ if (totalCount === 0 || !isPercentage) {
523
+ return value;
524
+ }
525
+ return Math.floor((value * totalCount) / 100);
526
+ }
527
+
528
+ protected calculateDistinctRowsCount(filter: FilterConfig, defaultCount: number): number {
529
+ if (filter.distinctRowsCount && filter.distinctRowsCount > 0) {
530
+ return filter.distinctRowsCount;
531
+ }
532
+
533
+ if (this.options.superFilters?.children) {
534
+ for (const child of this.options.superFilters.children) {
535
+ if (Array.isArray(child.filters) && child.filters.length > 0) {
536
+ const firstFilter = child.filters[0];
537
+ if (firstFilter.distinctRowsCount && firstFilter.distinctRowsCount > 0) {
538
+ return firstFilter.distinctRowsCount;
539
+ }
540
+ }
541
+ }
542
+ }
543
+
544
+ return defaultCount;
545
+ }
546
+
547
+ protected extractFilters(): {
548
+ columnName: string;
549
+ values: string[];
550
+ applicationType: string;
551
+ }[] {
552
+ if (!this.options.superFilters?.children) {
553
+ return [];
554
+ }
555
+
556
+ const filters: {
557
+ columnName: string;
558
+ values: string[];
559
+ applicationType: string;
560
+ }[] = [];
561
+
562
+ this.options.superFilters.children.forEach((child) => {
563
+ const filter = child.filters;
564
+ if (!filter) return;
565
+
566
+ switch (filter.filterType) {
567
+ case 'VALUES':
568
+ if (filter.columnNames?.length > 0) {
569
+ const columnName = filter.columnNames[0];
570
+ const values =
571
+ filter.valuesFilter
572
+ ?.flatMap((vf) => (Array.isArray(vf.id) ? vf.id : [vf.id]))
573
+ .filter((v) => v !== undefined) || [];
574
+ const applicationType = filter.valuesFilterApplicationType || 'include';
575
+
576
+ filters.push({
577
+ columnName,
578
+ values,
579
+ applicationType,
580
+ });
581
+ }
582
+ break;
583
+ case 'RANGE':
584
+ break;
585
+ case 'DATE':
586
+ break;
587
+ default:
588
+ break;
589
+ }
590
+ });
591
+
592
+ return filters;
593
+ }
594
+
595
+ protected applyLogicalOperator(conditions: string[], filter: FilterConfig): string {
596
+ if (!conditions.length) return '';
597
+ if (conditions.length === 1) return conditions[0];
598
+
599
+ const logicalOp = filter.logicalOperator?.toUpperCase() === 'OR' ? 'OR' : 'AND';
600
+ return conditions.join(` ${logicalOp} `);
601
+ }
602
+
603
+ protected handleTupleFilter(filter: FilterConfig): boolean {
604
+ return Boolean(filter.isTupleFilter || (filter.columnIds && filter.columnIds.length > 1));
605
+ }
606
+
607
+ protected handleCrossHighlight(filter: FilterConfig): boolean {
608
+ return Boolean(filter.isCrossHighlight);
609
+ }
610
+
611
+ protected validateDataTypes(filter: FilterConfig): boolean {
612
+ if (!filter.dataType?.length || !filter.columnDataType?.length) {
613
+ return true;
614
+ }
615
+ return filter.dataType.every((type) =>
616
+ ['string', 'number', 'date', 'boolean'].includes(type.toLowerCase()),
617
+ );
618
+ }
619
+
620
+ protected processSourceTypes(filter: FilterConfig): string[] {
621
+ return filter.sourceType || [];
622
+ }
623
+
624
+ protected isRankingFilterEnabled(filter: FilterConfig): boolean {
625
+ return Boolean(filter.isRankingFilter || filter.rankingConfig);
626
+ }
627
+ }