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,544 @@
1
+ import {
2
+ FilterConfig,
3
+ RangeFilter,
4
+ RankingConfig,
5
+ } from '@epm-query-builder/types/query-builder-types';
6
+ import { BaseUtilities } from '@epm-query-builder/base/BaseUtilities';
7
+ import * as ColumnRefUtils from '@epm-query-builder/base/ColumnRefUtils';
8
+
9
+ export class SharedFilterBuilder {
10
+ private static mapToCanonicalOperator(op: string): string {
11
+ const norm = (op || '')
12
+ .toLowerCase()
13
+ .replace(/[^a-z0-9]+/g, '_')
14
+ .replace(/^_+|_+$/g, '');
15
+ switch (norm) {
16
+ case 'contains':
17
+ return 'CONTAINS';
18
+ case 'does_not_contain':
19
+ case 'does_not_contains':
20
+ case 'not_contains':
21
+ case 'not_contain':
22
+ return 'DOES_NOT_CONTAIN';
23
+ case 'starts_with':
24
+ return 'STARTS_WITH';
25
+ case 'does_not_start_with':
26
+ case 'does_not_starts_with':
27
+ case 'not_starts_with':
28
+ case 'not_start_with':
29
+ return 'DOES_NOT_START_WITH';
30
+ case 'ends_with':
31
+ return 'ENDS_WITH';
32
+ case 'does_not_end_with':
33
+ case 'not_ends_with':
34
+ case 'not_end_with':
35
+ return 'DOES_NOT_END_WITH';
36
+ case 'equals':
37
+ case 'is_equal_to':
38
+ case 'is':
39
+ return 'EQUALS';
40
+ case 'not_equals':
41
+ case 'is_not_equal_to':
42
+ case 'is_not':
43
+ return 'NOT_EQUALS';
44
+ case 'is_blank':
45
+ case 'blank':
46
+ return 'IS_BLANK';
47
+ case 'is_not_blank':
48
+ case 'not_blank':
49
+ return 'IS_NOT_BLANK';
50
+ default:
51
+ return norm.toUpperCase();
52
+ }
53
+ }
54
+ static buildRangeCondition(column: string, range: RangeFilter): string {
55
+ const parts: string[] = [];
56
+
57
+ if (range.from !== undefined && range.fromCondition) {
58
+ parts.push(this.buildRangeOperatorCondition(column, range.fromCondition, range.from));
59
+ }
60
+
61
+ if (range.to !== undefined && range.toCondition) {
62
+ parts.push(this.buildRangeOperatorCondition(column, range.toCondition, range.to));
63
+ }
64
+
65
+ if (range.operator && range.value !== undefined) {
66
+ parts.push(this.buildRangeOperatorCondition(column, range.operator, range.value));
67
+ }
68
+
69
+ if (parts.length === 0) return '';
70
+
71
+ const joiner = (range.logicalOperator || 'AND').toUpperCase() === 'OR' ? 'OR' : 'AND';
72
+ return parts.length === 1 ? parts[0] : `(${parts.join(` ${joiner} `)})`;
73
+ }
74
+
75
+ private static buildRangeOperatorCondition(
76
+ column: string,
77
+ operator: string,
78
+ value: string | number | boolean,
79
+ ): string {
80
+ const operatorCode = this.mapToCanonicalOperator(operator);
81
+
82
+ const escapedValue = String(value).replace(/'/g, "''");
83
+
84
+ switch (operatorCode) {
85
+ case 'CONTAINS':
86
+ return `LOWER(${column}) LIKE LOWER('%${escapedValue}%')`;
87
+ case 'DOES_NOT_CONTAIN':
88
+ case 'NOT_CONTAINS':
89
+ case 'NOT CONTAINS':
90
+ return `LOWER(${column}) NOT LIKE LOWER('%${escapedValue}%')`;
91
+ case 'STARTS_WITH':
92
+ return `LOWER(${column}) LIKE LOWER('${escapedValue}%')`;
93
+ case 'DOES_NOT_START_WITH':
94
+ case 'NOT_STARTS_WITH':
95
+ case 'NOT STARTS WITH':
96
+ return `LOWER(${column}) NOT LIKE LOWER('${escapedValue}%')`;
97
+ case 'ENDS_WITH':
98
+ return `LOWER(${column}) LIKE LOWER('%${escapedValue}')`;
99
+ case 'DOES_NOT_END_WITH':
100
+ case 'NOT_ENDS_WITH':
101
+ case 'NOT ENDS WITH':
102
+ return `LOWER(${column}) NOT LIKE LOWER('%${escapedValue}')`;
103
+ case 'EQUALS':
104
+ case 'IS_EQUAL_TO':
105
+ case 'IS':
106
+ return BaseUtilities.buildFilterConditionForOperator(column, 'IS_EQUAL_TO', value);
107
+ case 'NOT_EQUALS':
108
+ case 'IS_NOT_EQUAL_TO':
109
+ case 'IS_NOT':
110
+ return BaseUtilities.buildFilterConditionForOperator(column, 'IS_NOT_EQUAL_TO', value);
111
+ case 'IS_GREATER_THAN':
112
+ return BaseUtilities.buildFilterConditionForOperator(column, 'IS_GREATER_THAN', value);
113
+ case 'IS_GREATER_THAN_OR_EQUAL_TO':
114
+ return BaseUtilities.buildFilterConditionForOperator(
115
+ column,
116
+ 'IS_GREATER_THAN_OR_EQUAL_TO',
117
+ value,
118
+ );
119
+ case 'IS_LESS_THAN':
120
+ return BaseUtilities.buildFilterConditionForOperator(column, 'IS_LESS_THAN', value);
121
+ case 'IS_LESS_THAN_OR_EQUAL_TO':
122
+ return BaseUtilities.buildFilterConditionForOperator(
123
+ column,
124
+ 'IS_LESS_THAN_OR_EQUAL_TO',
125
+ value,
126
+ );
127
+ case 'IS_BLANK':
128
+ return BaseUtilities.buildFilterConditionForOperator(column, 'IS_BLANK', '');
129
+ case 'IS_NOT_BLANK':
130
+ return BaseUtilities.buildFilterConditionForOperator(column, 'IS_NOT_BLANK', '');
131
+ case 'IS_EMPTY':
132
+ return `TRIM(${column}) = ''`;
133
+ case 'IS_NOT_EMPTY':
134
+ return `TRIM(${column}) != ''`;
135
+ default:
136
+ return `LOWER(${column}) LIKE LOWER('%${escapedValue}%')`;
137
+ }
138
+ }
139
+
140
+ static buildRangeFilter(filter: FilterConfig): string {
141
+ if (!filter.columnNames?.length || !filter.rangeFilter?.length) {
142
+ return '';
143
+ }
144
+
145
+ const column = this.getColumnReference(filter);
146
+ const conditions = filter.rangeFilter
147
+ .map((range) => this.buildRangeCondition(column, range))
148
+ .filter((condition) => condition);
149
+
150
+ return BaseUtilities.combineConditions(
151
+ conditions,
152
+ (filter.logicalOperator as 'AND' | 'OR') || 'AND',
153
+ );
154
+ }
155
+
156
+ static buildValuesFilter(filter: FilterConfig): string {
157
+ if (!filter.columnNames?.length || !filter.valuesFilter?.length) {
158
+ return '';
159
+ }
160
+
161
+ const column = this.getColumnReference(filter);
162
+ const values = filter.valuesFilter
163
+ .flatMap((vf) => (Array.isArray(vf.id) ? vf.id : [vf.id]))
164
+ .filter((v) => v !== undefined);
165
+
166
+ if (values.length === 0) return '';
167
+
168
+ const operator =
169
+ filter.valuesFilterApplicationType?.toUpperCase() === 'EXCLUDE' ? 'NOT IN' : 'IN';
170
+ const valueList = values.map((v) => BaseUtilities.formatValue(v.toString())).join(',');
171
+
172
+ return `${column} ${operator} (${valueList})`;
173
+ }
174
+
175
+ static buildRankingFilter(filter: FilterConfig): string {
176
+ const rankingConfigs =
177
+ filter.rankingFilter || (filter.rankingConfig ? [filter.rankingConfig] : []);
178
+
179
+ if (!rankingConfigs.length || !filter.columnNames?.length) {
180
+ return '';
181
+ }
182
+
183
+ const conditions = rankingConfigs.map((rankingConfig) =>
184
+ this.buildSingleRankingCondition(filter, rankingConfig),
185
+ );
186
+
187
+ return BaseUtilities.combineConditions(
188
+ conditions,
189
+ (filter.logicalOperator as 'AND' | 'OR') || 'AND',
190
+ );
191
+ }
192
+
193
+ private static buildSingleRankingCondition(
194
+ filter: FilterConfig,
195
+ rankingConfig: RankingConfig,
196
+ ): string {
197
+ const column = filter.columnNames![0];
198
+ const tableName = filter.tableNames?.[0] || rankingConfig.rankByTableName || '';
199
+
200
+ const rankByColumnId =
201
+ rankingConfig.rankByColumnId ||
202
+ `${rankingConfig.rankByTableName || ''}[${rankingConfig.rankByColumnName || column}]`;
203
+ const actualColumnId = BaseUtilities.extractColumnIdFromHierarchy(rankByColumnId);
204
+
205
+ const rankByColumnRef = tableName
206
+ ? BaseUtilities.buildColumnReference(tableName, actualColumnId)
207
+ : `"${actualColumnId}"`;
208
+
209
+ const aggregationType = BaseUtilities.mapAggregationType(
210
+ rankingConfig.rankByAggregationType || 'SUM',
211
+ );
212
+ const orderDirection = rankingConfig.type === 'TOP' ? 'DESC' : 'ASC';
213
+
214
+ const measureExpression =
215
+ aggregationType !== 'NONE' ? `${aggregationType}(${rankByColumnRef})` : rankByColumnRef;
216
+
217
+ if (rankingConfig.isPercentage) {
218
+ const percentileValue = rankingConfig.value / 100;
219
+ return `PERCENT_RANK() OVER (ORDER BY ${measureExpression} ${orderDirection}) <= ${percentileValue}`;
220
+ } else {
221
+ return `ROW_NUMBER() OVER (ORDER BY ${measureExpression} ${orderDirection}) <= ${rankingConfig.value}`;
222
+ }
223
+ }
224
+
225
+ static buildSearchFilter(filter: FilterConfig): string {
226
+ if (!filter.columnNames?.length || !filter.searchConditions?.length) {
227
+ return '';
228
+ }
229
+
230
+ const column = this.getColumnReference(filter);
231
+ const conditions = filter.searchConditions.map((condition) => {
232
+ const operatorCode = this.mapToCanonicalOperator(condition.operator || '');
233
+ const rawValue = String(condition.value ?? '');
234
+ const escapedValue = rawValue.replace(/'/g, "''");
235
+
236
+ switch (operatorCode) {
237
+ case 'CONTAINS':
238
+ return `LOWER(${column}) LIKE LOWER('%${escapedValue}%')`;
239
+ case 'DOES_NOT_CONTAIN':
240
+ return `LOWER(${column}) NOT LIKE LOWER('%${escapedValue}%')`;
241
+ case 'STARTS_WITH':
242
+ return `LOWER(${column}) LIKE LOWER('${escapedValue}%')`;
243
+ case 'DOES_NOT_START_WITH':
244
+ return `LOWER(${column}) NOT LIKE LOWER('${escapedValue}%')`;
245
+ case 'ENDS_WITH':
246
+ return `LOWER(${column}) LIKE LOWER('%${escapedValue}')`;
247
+ case 'DOES_NOT_END_WITH':
248
+ return `LOWER(${column}) NOT LIKE LOWER('%${escapedValue}')`;
249
+ case 'EQUALS':
250
+ return `${column} = ${BaseUtilities.formatValue(rawValue)}`;
251
+ case 'NOT_EQUALS':
252
+ return `${column} != ${BaseUtilities.formatValue(rawValue)}`;
253
+ case 'IS_BLANK':
254
+ return `${column} IS NULL`;
255
+ case 'IS_NOT_BLANK':
256
+ return `${column} IS NOT NULL`;
257
+ case 'IS_EMPTY':
258
+ return `TRIM(${column}) = ''`;
259
+ case 'IS_NOT_EMPTY':
260
+ return `TRIM(${column}) != ''`;
261
+ default:
262
+ return `LOWER(${column}) LIKE LOWER('%${escapedValue}%')`;
263
+ }
264
+ });
265
+
266
+ return BaseUtilities.combineConditions(conditions, 'AND');
267
+ }
268
+
269
+ static buildBlankFilter(filter: FilterConfig): string {
270
+ if (!filter.columnNames?.length || !filter.blankFilterConfig) {
271
+ return '';
272
+ }
273
+
274
+ const column = this.getColumnReference(filter);
275
+ const blankConfig = filter.blankFilterConfig;
276
+
277
+ if (blankConfig.operator === 'IS_BLANK') {
278
+ if (blankConfig.treatEmptyStringAsBlank) {
279
+ return `(${column} IS NULL OR TRIM(${column}) = '')`;
280
+ } else {
281
+ return `${column} IS NULL`;
282
+ }
283
+ } else {
284
+ if (blankConfig.treatEmptyStringAsBlank) {
285
+ return `(${column} IS NOT NULL AND TRIM(${column}) != '')`;
286
+ } else {
287
+ return `${column} IS NOT NULL`;
288
+ }
289
+ }
290
+ }
291
+
292
+ static buildTupleFilter(filter: FilterConfig): string {
293
+ if (!filter.columnNames?.length || !filter.valuesFilter?.length) {
294
+ return '';
295
+ }
296
+
297
+ const columns = filter.columnNames;
298
+ const tupleConditions: string[] = [];
299
+
300
+ filter.valuesFilter.forEach((valueItem) => {
301
+ if (Array.isArray(valueItem.id)) {
302
+ const tupleValues = valueItem.id
303
+ .map((id, index) => `${columns[index]} = ${BaseUtilities.formatValue(id.toString())}`)
304
+ .join(' AND ');
305
+ tupleConditions.push(`(${tupleValues})`);
306
+ }
307
+ });
308
+
309
+ if (tupleConditions.length === 0) return '';
310
+
311
+ const isInclude = filter.valuesFilterApplicationType === 'INCLUDE';
312
+ if (tupleConditions.length === 1) {
313
+ return tupleConditions[0];
314
+ }
315
+ const joiner = isInclude ? ' OR ' : ' AND NOT ';
316
+ const combined = tupleConditions.join(joiner);
317
+ return `(${combined})`;
318
+ }
319
+
320
+ static buildRelativePeriodFilter(filter: FilterConfig): string {
321
+ if (!filter.columnNames?.length || !filter.relativePeriodFilter) {
322
+ return '';
323
+ }
324
+
325
+ const column = this.getColumnReference(filter);
326
+ return this.buildRelativePeriodCondition(column, filter.relativePeriodFilter);
327
+ }
328
+
329
+ static buildDateHierarchyFilter(filter: FilterConfig): string {
330
+ if (!filter.columnNames?.length || !filter.dateHierarchyConfig) {
331
+ return '';
332
+ }
333
+
334
+ const tableName = filter.tableNames?.[0];
335
+ const column = BaseUtilities.buildColumnReference(tableName, filter.columnNames[0]);
336
+ const hierarchyConfig = filter.dateHierarchyConfig;
337
+
338
+ if (!hierarchyConfig.level) {
339
+ return `${column} IS NOT NULL`;
340
+ }
341
+
342
+ if (!hierarchyConfig.values?.length) {
343
+ let hierarchyFunction: string;
344
+ switch (hierarchyConfig.level) {
345
+ case 'YEAR':
346
+ hierarchyFunction = `EXTRACT(YEAR FROM ${column})`;
347
+ break;
348
+ case 'QUARTER':
349
+ hierarchyFunction = `EXTRACT(QUARTER FROM ${column})`;
350
+ break;
351
+ case 'MONTH':
352
+ hierarchyFunction = `EXTRACT(MONTH FROM ${column})`;
353
+ break;
354
+ case 'DAY':
355
+ hierarchyFunction = `EXTRACT(DAY FROM ${column})`;
356
+ break;
357
+ case 'WEEK':
358
+ hierarchyFunction = `EXTRACT(WEEK FROM ${column})`;
359
+ break;
360
+ case 'DAYOFWEEK':
361
+ hierarchyFunction = `EXTRACT(DAYOFWEEK FROM ${column})`;
362
+ break;
363
+ default:
364
+ return `${column} IS NOT NULL`;
365
+ }
366
+ return `${hierarchyFunction} IS NOT NULL`;
367
+ }
368
+
369
+ let hierarchyFunction: string;
370
+ switch (hierarchyConfig.level) {
371
+ case 'YEAR':
372
+ hierarchyFunction = `EXTRACT(YEAR FROM ${column})`;
373
+ break;
374
+ case 'QUARTER':
375
+ hierarchyFunction = `EXTRACT(QUARTER FROM ${column})`;
376
+ break;
377
+ case 'MONTH':
378
+ hierarchyFunction = `EXTRACT(MONTH FROM ${column})`;
379
+ break;
380
+ case 'DAY':
381
+ hierarchyFunction = `EXTRACT(DAY FROM ${column})`;
382
+ break;
383
+ case 'WEEK':
384
+ hierarchyFunction = `EXTRACT(WEEK FROM ${column})`;
385
+ break;
386
+ case 'DAYOFWEEK':
387
+ hierarchyFunction = `EXTRACT(DAYOFWEEK FROM ${column})`;
388
+ break;
389
+ default:
390
+ return `${column} IS NOT NULL`;
391
+ }
392
+
393
+ if (hierarchyConfig.values.length === 1) {
394
+ return `${hierarchyFunction} = ${hierarchyConfig.values[0]}`;
395
+ } else {
396
+ const valuesList = hierarchyConfig.values.join(', ');
397
+ return `${hierarchyFunction} IN (${valuesList})`;
398
+ }
399
+ }
400
+
401
+ static buildFieldParameterFilter(filter: FilterConfig): string {
402
+ if (!filter.fieldParameterMapping) {
403
+ return '';
404
+ }
405
+
406
+ const mapping = filter.fieldParameterMapping;
407
+ if (!mapping.targetField) {
408
+ return '';
409
+ }
410
+
411
+ const tableName = mapping.targetTable;
412
+ const column = BaseUtilities.buildColumnReference(tableName, mapping.targetField);
413
+
414
+ if (mapping.filterValues?.length) {
415
+ if (mapping.filterValues.length === 1) {
416
+ return `${column} = '${mapping.filterValues[0]}'`;
417
+ } else {
418
+ const valuesList = mapping.filterValues.map((v) => `'${v}'`).join(', ');
419
+ return `${column} IN (${valuesList})`;
420
+ }
421
+ }
422
+
423
+ return `${column} IS NOT NULL`;
424
+ }
425
+
426
+ static buildDateFilter(filter: FilterConfig): string {
427
+ if (!filter.dateRangeFilter?.length) return '';
428
+
429
+ const column = this.getColumnReference(filter);
430
+ const conditions = filter.dateRangeFilter.map((dateRange) => {
431
+ const startDate = BaseUtilities.stringToDate(dateRange.startDate);
432
+ const endDate = BaseUtilities.stringToDate(dateRange.endDate);
433
+ return `${column} BETWEEN ${startDate} AND ${endDate}`;
434
+ });
435
+
436
+ return BaseUtilities.combineConditions(conditions, 'AND');
437
+ }
438
+
439
+ private static getColumnReference(filter: FilterConfig): string {
440
+ const columnId = filter.columnIds?.[0];
441
+ const columnFromName = filter.columnNames?.[0];
442
+ const tableName =
443
+ filter.tableNames?.[0] ||
444
+ (columnId ? ColumnRefUtils.getTableNameFromId(columnId) || undefined : undefined);
445
+
446
+ if (columnId) {
447
+ const actualId = BaseUtilities.extractColumnIdFromHierarchy(columnId);
448
+ const columnOnly = ColumnRefUtils.getColumnNameFromId(actualId);
449
+ return tableName
450
+ ? BaseUtilities.buildColumnReference(tableName, columnOnly)
451
+ : `"${columnOnly}"`;
452
+ }
453
+
454
+ if (columnFromName) {
455
+ return tableName
456
+ ? BaseUtilities.buildColumnReference(tableName, columnFromName)
457
+ : `"${columnFromName}"`;
458
+ }
459
+ return '';
460
+ }
461
+
462
+ static buildFilterCondition(filter: FilterConfig): string {
463
+ if (!filter) return '';
464
+
465
+ switch (filter.filterType?.toUpperCase()) {
466
+ case 'VALUES':
467
+ return this.buildValuesFilter(filter);
468
+ case 'RANGE':
469
+ return this.buildRangeFilter(filter);
470
+ case 'DATE':
471
+ case 'DATE_RANGE':
472
+ return this.buildDateFilter(filter);
473
+ case 'RANKING':
474
+ return this.buildRankingFilter(filter);
475
+ case 'SEARCH':
476
+ return this.buildSearchFilter(filter);
477
+ case 'BLANK':
478
+ return this.buildBlankFilter(filter);
479
+ case 'TUPLE':
480
+ return this.buildTupleFilter(filter);
481
+ case 'RELATIVE_PERIOD':
482
+ return this.buildRelativePeriodFilter(filter);
483
+ case 'DATE_HIERARCHY':
484
+ return this.buildDateHierarchyFilter(filter);
485
+ case 'FIELD_PARAMETER':
486
+ return this.buildFieldParameterFilter(filter);
487
+ default:
488
+ return '';
489
+ }
490
+ }
491
+
492
+ static buildRelativePeriodCondition(
493
+ column: string,
494
+ config: { duration: number; period: string; relativeDateFilter: string },
495
+ ): string {
496
+ const now = 'CURRENT_DATE';
497
+ const duration = config.duration;
498
+ const period = config.period;
499
+
500
+ switch (config.relativeDateFilter) {
501
+ case 'IS_IN_THE_LAST':
502
+ switch (period) {
503
+ case 'DAYS':
504
+ return `${column} >= ${now} - INTERVAL '${duration} days'`;
505
+ case 'WEEKS':
506
+ return `${column} >= ${now} - INTERVAL '${duration} weeks'`;
507
+ case 'MONTHS':
508
+ return `${column} >= ${now} - INTERVAL '${duration} months'`;
509
+ case 'YEARS':
510
+ return `${column} >= ${now} - INTERVAL '${duration} years'`;
511
+ default:
512
+ return `${column} >= ${now} - INTERVAL '${duration} days'`;
513
+ }
514
+ case 'IS_IN_THE_NEXT':
515
+ switch (period) {
516
+ case 'DAYS':
517
+ return `${column} <= ${now} + INTERVAL '${duration} days'`;
518
+ case 'WEEKS':
519
+ return `${column} <= ${now} + INTERVAL '${duration} weeks'`;
520
+ case 'MONTHS':
521
+ return `${column} <= ${now} + INTERVAL '${duration} months'`;
522
+ case 'YEARS':
523
+ return `${column} <= ${now} + INTERVAL '${duration} years'`;
524
+ default:
525
+ return `${column} <= ${now} + INTERVAL '${duration} days'`;
526
+ }
527
+ case 'IS_IN_THIS':
528
+ switch (period) {
529
+ case 'DAYS':
530
+ return `DATE_TRUNC('day', ${column}) = DATE_TRUNC('day', ${now})`;
531
+ case 'WEEKS':
532
+ return `DATE_TRUNC('week', ${column}) = DATE_TRUNC('week', ${now})`;
533
+ case 'MONTHS':
534
+ return `DATE_TRUNC('month', ${column}) = DATE_TRUNC('month', ${now})`;
535
+ case 'YEARS':
536
+ return `DATE_TRUNC('year', ${column}) = DATE_TRUNC('year', ${now})`;
537
+ default:
538
+ return `DATE_TRUNC('day', ${column}) = DATE_TRUNC('day', ${now})`;
539
+ }
540
+ default:
541
+ return `${column} = ${now}`;
542
+ }
543
+ }
544
+ }
@@ -0,0 +1,16 @@
1
+ export const AGGREGATION_TYPE_MAP: Record<string, string> = {
2
+ FIRST: 'MIN',
3
+ LAST: 'MAX',
4
+ STANDARD_DEVIATION: 'STDDEV',
5
+ VARIANCE: 'VAR',
6
+ AVERAGE: 'AVG',
7
+ COUNT_DISTINCT: 'COUNT',
8
+ DISTINCT_COUNT: 'COUNT',
9
+ COUNT: 'COUNT',
10
+ };
11
+
12
+ export function mapAggregationType(aggregationType?: string): string {
13
+ if (!aggregationType) return 'SUM';
14
+ const key = aggregationType.toUpperCase();
15
+ return AGGREGATION_TYPE_MAP[key] || key;
16
+ }
@@ -0,0 +1,6 @@
1
+ // list of supported databases for epm query builder
2
+ export const DATABASE_TYPES = {
3
+ DUCKDB: 'duckdb',
4
+ } as const;
5
+
6
+ export type DatabaseType = (typeof DATABASE_TYPES)[keyof typeof DATABASE_TYPES];
@@ -0,0 +1,7 @@
1
+ // Source types for epm query builder
2
+ export const SOURCE_TYPES = {
3
+ BLEND: 'blend',
4
+ XMLA: 'xmla',
5
+ } as const;
6
+
7
+ export type SourceType = (typeof SOURCE_TYPES)[keyof typeof SOURCE_TYPES];
@@ -0,0 +1,67 @@
1
+ import {
2
+ MeasureConfig,
3
+ EpmQueryBuilderOptions,
4
+ } from '@epm-query-builder/types/query-builder-types';
5
+ import { BaseAdvancedAggregations } from '@epm-query-builder/base/BaseAdvancedAggregations';
6
+ import { BaseUtilities } from '@epm-query-builder/base/BaseUtilities';
7
+
8
+ export class DuckDbAdvancedAggregations extends BaseAdvancedAggregations {
9
+ constructor(options: EpmQueryBuilderOptions) {
10
+ super(options);
11
+ }
12
+
13
+ buildHistogramAggregation(measure: MeasureConfig, binCount = 10): string {
14
+ const columnRef = BaseUtilities.buildColumnReference(
15
+ measure.tableName,
16
+ measure.columnName || measure.id,
17
+ );
18
+
19
+ return `HISTOGRAM(${columnRef}) WITH ${binCount} BINS`;
20
+ }
21
+
22
+ buildReservoirSample(measure: MeasureConfig, sampleSize: number): string {
23
+ const columnRef = BaseUtilities.buildColumnReference(
24
+ measure.tableName,
25
+ measure.columnName || measure.id,
26
+ );
27
+
28
+ return `RESERVOIR_SAMPLE(${columnRef}, ${sampleSize})`;
29
+ }
30
+
31
+ buildQuantileAggregation(measure: MeasureConfig, quantiles: number[]): string {
32
+ const columnRef = BaseUtilities.buildColumnReference(
33
+ measure.tableName,
34
+ measure.columnName || measure.id,
35
+ );
36
+ const quantileList = quantiles.join(', ');
37
+
38
+ return `QUANTILE(${columnRef}, [${quantileList}])`;
39
+ }
40
+
41
+ buildMadAggregation(measure: MeasureConfig): string {
42
+ const columnRef = BaseUtilities.buildColumnReference(
43
+ measure.tableName,
44
+ measure.columnName || measure.id,
45
+ );
46
+
47
+ return `MAD(${columnRef})`;
48
+ }
49
+
50
+ buildModeAggregation(measure: MeasureConfig): string {
51
+ const columnRef = BaseUtilities.buildColumnReference(
52
+ measure.tableName,
53
+ measure.columnName || measure.id,
54
+ );
55
+
56
+ return `MODE(${columnRef})`;
57
+ }
58
+
59
+ buildProductAggregation(measure: MeasureConfig): string {
60
+ const columnRef = BaseUtilities.buildColumnReference(
61
+ measure.tableName,
62
+ measure.columnName || measure.id,
63
+ );
64
+
65
+ return `PRODUCT(${columnRef})`;
66
+ }
67
+ }