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,131 @@
|
|
|
1
|
+
import { BaseRollupBuilder } from '@epm-query-builder/base/BaseRollupBuilder';
|
|
2
|
+
import { BaseUtilities } from '@epm-query-builder/base/BaseUtilities';
|
|
3
|
+
|
|
4
|
+
export class DuckDbRollupBuilder extends BaseRollupBuilder {
|
|
5
|
+
buildGroupByClause(): string {
|
|
6
|
+
if (!this.shouldGenerateRollup()) {
|
|
7
|
+
return this.buildBasicGroupByClause();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const groupingSets = this.buildGroupingSets();
|
|
11
|
+
if (!groupingSets) {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
return `GROUP BY ${groupingSets}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
buildRollupSelects(): string[] {
|
|
18
|
+
if (!this.shouldGenerateRollup()) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const selects: string[] = [];
|
|
23
|
+
|
|
24
|
+
selects.push(...this.buildRollupTotalIndicators());
|
|
25
|
+
|
|
26
|
+
return selects;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
buildNullFilterConditions(): string[] {
|
|
30
|
+
if (!this.shouldGenerateRollup()) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const dimensions = this.getDimensions();
|
|
35
|
+
if (dimensions.length === 0) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return dimensions.map((dim) => `${dim} IS NOT NULL`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private buildGroupingIndicators(): string[] {
|
|
43
|
+
const dimensions = this.getDimensions();
|
|
44
|
+
const indicators: string[] = [];
|
|
45
|
+
dimensions.forEach(() => {
|
|
46
|
+
// intentionally omitted raw GROUPING columns from the sql output, need to handle separately in the case of IB
|
|
47
|
+
});
|
|
48
|
+
return indicators;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private buildRollupTotalIndicators(): string[] {
|
|
52
|
+
const indicators: string[] = [];
|
|
53
|
+
const rowCount = this.options.rows?.length || 0;
|
|
54
|
+
const columnCount = this.options.columns?.length || 0;
|
|
55
|
+
|
|
56
|
+
if (rowCount > 0) {
|
|
57
|
+
const rowDimensions = this.getRowDimensions();
|
|
58
|
+
|
|
59
|
+
if (rowDimensions.length > 0) {
|
|
60
|
+
const groupingCondition = rowDimensions
|
|
61
|
+
.map((_, index) => `GROUPING(${rowDimensions[index]}) = 1`)
|
|
62
|
+
.join(' AND ');
|
|
63
|
+
|
|
64
|
+
indicators.push(
|
|
65
|
+
`CASE WHEN ${groupingCondition} THEN true ELSE false END AS "[IsRowGrandTotal]"`,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
for (let i = 1; i < rowCount; i++) {
|
|
69
|
+
const partialGroupingCondition = rowDimensions
|
|
70
|
+
.slice(i)
|
|
71
|
+
.map((_, idx) => `GROUPING(${rowDimensions[i + idx]}) = 1`)
|
|
72
|
+
.join(' AND ');
|
|
73
|
+
|
|
74
|
+
const nonGroupingCondition = rowDimensions
|
|
75
|
+
.slice(0, i)
|
|
76
|
+
.map((_, idx) => `GROUPING(${rowDimensions[idx]}) = 0`)
|
|
77
|
+
.join(' AND ');
|
|
78
|
+
|
|
79
|
+
const dmCondition =
|
|
80
|
+
i === 1
|
|
81
|
+
? `(${nonGroupingCondition} AND ${partialGroupingCondition}) OR (${groupingCondition})`
|
|
82
|
+
: `${nonGroupingCondition} AND ${partialGroupingCondition}`;
|
|
83
|
+
|
|
84
|
+
indicators.push(
|
|
85
|
+
`CASE WHEN ${dmCondition} THEN true ELSE false END AS "[IsDM${i - 1}Total]"`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (columnCount > 0) {
|
|
92
|
+
const columnDimensions = this.getColumnDimensions();
|
|
93
|
+
|
|
94
|
+
if (columnDimensions.length > 0) {
|
|
95
|
+
const groupingCondition = columnDimensions
|
|
96
|
+
.map((_, index) => `GROUPING(${columnDimensions[index]}) = 1`)
|
|
97
|
+
.join(' AND ');
|
|
98
|
+
|
|
99
|
+
indicators.push(
|
|
100
|
+
`CASE WHEN ${groupingCondition} THEN true ELSE false END AS "[IsColumnGrandTotal]"`,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
for (let i = 1; i < columnCount; i++) {
|
|
104
|
+
const partialGroupingCondition = columnDimensions
|
|
105
|
+
.slice(i)
|
|
106
|
+
.map((_, idx) => `GROUPING(${columnDimensions[i + idx]}) = 1`)
|
|
107
|
+
.join(' AND ');
|
|
108
|
+
|
|
109
|
+
const nonGroupingCondition = columnDimensions
|
|
110
|
+
.slice(0, i)
|
|
111
|
+
.map((_, idx) => `GROUPING(${columnDimensions[idx]}) = 0`)
|
|
112
|
+
.join(' AND ');
|
|
113
|
+
|
|
114
|
+
indicators.push(
|
|
115
|
+
`CASE WHEN ${nonGroupingCondition} AND ${partialGroupingCondition} THEN true ELSE false END AS "[IsDM${rowCount + i - 1}Total]"`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return indicators;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private getRowDimensions(): string[] {
|
|
125
|
+
return BaseUtilities.buildDimensionReference(this.options.rows, this.options);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private getColumnDimensions(): string[] {
|
|
129
|
+
return BaseUtilities.buildDimensionReference(this.options.columns, this.options);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { BaseSuperFilterBuilder } from '@epm-query-builder/base/BaseSuperFilterBuilder';
|
|
2
|
+
import { FilterConfig, EpmQueryBuilderOptions } from '@epm-query-builder/types/query-builder-types';
|
|
3
|
+
import { BaseCTEGenerator } from '@epm-query-builder/base/BaseCTEGenerator';
|
|
4
|
+
import { BaseUtilities } from '@epm-query-builder/base/BaseUtilities';
|
|
5
|
+
import { SharedFilterBuilder } from '@epm-query-builder/base/SharedFilterBuilder';
|
|
6
|
+
import { SOURCE_TYPES } from '@epm-query-builder/constants/Source';
|
|
7
|
+
|
|
8
|
+
export class DuckDbSuperFilterBuilder extends BaseSuperFilterBuilder {
|
|
9
|
+
private cteGenerator: BaseCTEGenerator;
|
|
10
|
+
|
|
11
|
+
constructor(options: EpmQueryBuilderOptions) {
|
|
12
|
+
super(options);
|
|
13
|
+
this.cteGenerator = new (class extends BaseCTEGenerator {
|
|
14
|
+
buildSpecificFilterCTE(filter: FilterConfig, variableName: string): string {
|
|
15
|
+
if (filter.filterType?.toUpperCase() === 'RANKING') {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
const source = BaseUtilities.getSource(this.options);
|
|
19
|
+
if (source === SOURCE_TYPES.BLEND) {
|
|
20
|
+
const fromIds = filter.columnIds || [];
|
|
21
|
+
const fromNames = filter.columnNames || [];
|
|
22
|
+
const resolvedNames: string[] = [];
|
|
23
|
+
const maxLen = Math.max(fromIds.length, fromNames.length);
|
|
24
|
+
for (let i = 0; i < Math.max(maxLen, 1); i += 1) {
|
|
25
|
+
const id = fromIds[i];
|
|
26
|
+
const name = fromNames[i];
|
|
27
|
+
if (id) {
|
|
28
|
+
resolvedNames.push(id);
|
|
29
|
+
} else if (name) {
|
|
30
|
+
resolvedNames.push(name);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const adjusted: FilterConfig = {
|
|
34
|
+
...filter,
|
|
35
|
+
columnNames: resolvedNames.length ? resolvedNames : filter.columnNames,
|
|
36
|
+
columnIds: [],
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const condition = SharedFilterBuilder.buildFilterCondition(adjusted);
|
|
40
|
+
if (!condition) return '';
|
|
41
|
+
|
|
42
|
+
const tableName = adjusted.tableNames?.[0] || '';
|
|
43
|
+
const useDot = BaseUtilities.shouldUseDotNotation(this.options);
|
|
44
|
+
const tableForRef =
|
|
45
|
+
tableName || BaseUtilities.getDefaultTableNameFromOptions(this.options);
|
|
46
|
+
const selectColumnName = adjusted.columnNames?.[0] || '';
|
|
47
|
+
const columnRef = useDot
|
|
48
|
+
? BaseUtilities.buildColumnReference(tableForRef, selectColumnName)
|
|
49
|
+
: `"${selectColumnName}"`;
|
|
50
|
+
|
|
51
|
+
return BaseUtilities.buildDistinctSelect([columnRef], tableName, condition);
|
|
52
|
+
}
|
|
53
|
+
return this.buildComplexFilterCTE(filter, variableName);
|
|
54
|
+
}
|
|
55
|
+
protected isComplexFilter(filter: FilterConfig): boolean {
|
|
56
|
+
if (filter.filterType?.toUpperCase() === 'RANKING') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return super.isComplexFilter(filter);
|
|
60
|
+
}
|
|
61
|
+
})(options);
|
|
62
|
+
}
|
|
63
|
+
buildWhereClause(): string {
|
|
64
|
+
if (!this.options.superFilters) {
|
|
65
|
+
return '';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this.buildNestedFilterGroups(this.options.superFilters);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
buildFilterCTE(): string {
|
|
72
|
+
const complex = this.hasComplexFilters() ? this.cteGenerator.generateFilterCTEs() : '';
|
|
73
|
+
const orGroup = this.buildOrGroupCTE();
|
|
74
|
+
|
|
75
|
+
if (!complex && !orGroup) return '';
|
|
76
|
+
|
|
77
|
+
const complexDefs = complex.replace(/^\s*WITH\s+/i, '');
|
|
78
|
+
|
|
79
|
+
if (complexDefs && !orGroup) return complexDefs;
|
|
80
|
+
if (!complexDefs && orGroup) return orGroup;
|
|
81
|
+
|
|
82
|
+
return `${complexDefs},\n${orGroup}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected buildMeasureFilter(): string {
|
|
86
|
+
const measureFilters = this.extractMeasureFilters();
|
|
87
|
+
if (measureFilters.length === 0) {
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const conditions = measureFilters.map((filter) => this.buildMeasureCondition(filter));
|
|
92
|
+
return BaseUtilities.combineConditions(
|
|
93
|
+
conditions.filter((c) => c),
|
|
94
|
+
'AND',
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
protected buildValuesFilter(filter: FilterConfig): string {
|
|
99
|
+
if (!filter.columnNames?.length || !filter.valuesFilter?.length) {
|
|
100
|
+
return '';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const source = BaseUtilities.getSource(this.options);
|
|
104
|
+
const columnFromIds = filter.columnIds?.[0];
|
|
105
|
+
const columnFromNames = filter.columnNames[0];
|
|
106
|
+
const resolvedForDb =
|
|
107
|
+
source === SOURCE_TYPES.BLEND
|
|
108
|
+
? columnFromIds || columnFromNames
|
|
109
|
+
: BaseUtilities.extractColumnIdFromHierarchy(columnFromIds || columnFromNames);
|
|
110
|
+
const useDot = BaseUtilities.shouldUseDotNotation(this.options);
|
|
111
|
+
const columnReference = useDot
|
|
112
|
+
? BaseUtilities.buildColumnReference(
|
|
113
|
+
filter.tableNames?.[0] || BaseUtilities.getDefaultTableNameFromOptions(this.options),
|
|
114
|
+
resolvedForDb,
|
|
115
|
+
)
|
|
116
|
+
: `"${resolvedForDb}"`;
|
|
117
|
+
|
|
118
|
+
const values = filter.valuesFilter
|
|
119
|
+
.flatMap((vf) => (Array.isArray(vf.id) ? vf.id : [vf.id]))
|
|
120
|
+
.filter((v) => v !== undefined);
|
|
121
|
+
|
|
122
|
+
if (values.length === 0) {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (filter.isCrossHighlight === true) {
|
|
127
|
+
return SharedFilterBuilder.buildValuesFilter(this.adjustFilterForBlend(filter));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const operator =
|
|
131
|
+
filter.valuesFilterApplicationType?.toUpperCase() === 'INCLUDE' ? 'IN' : 'NOT IN';
|
|
132
|
+
const valueList = values.map((v) => BaseUtilities.formatValue(v.toString())).join(',');
|
|
133
|
+
|
|
134
|
+
return `${columnReference} ${operator} (${valueList})`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private adjustFilterForBlend(filter: FilterConfig): FilterConfig {
|
|
138
|
+
const src = BaseUtilities.getSource(this.options);
|
|
139
|
+
if (src !== SOURCE_TYPES.BLEND) return filter;
|
|
140
|
+
const fromIds = filter.columnIds || [];
|
|
141
|
+
const fromNames = filter.columnNames || [];
|
|
142
|
+
const resolvedNames: string[] = [];
|
|
143
|
+
const maxLen = Math.max(fromIds.length, fromNames.length);
|
|
144
|
+
for (let i = 0; i < Math.max(maxLen, 1); i += 1) {
|
|
145
|
+
const id = fromIds[i];
|
|
146
|
+
const name = fromNames[i];
|
|
147
|
+
if (id) {
|
|
148
|
+
resolvedNames.push(id);
|
|
149
|
+
} else if (name) {
|
|
150
|
+
resolvedNames.push(name);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
...filter,
|
|
155
|
+
columnNames: resolvedNames.length ? resolvedNames : filter.columnNames,
|
|
156
|
+
columnIds: [],
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
protected buildFilterCondition(filter: FilterConfig): string {
|
|
161
|
+
if (!filter) return '';
|
|
162
|
+
const type = filter.filterType?.toUpperCase();
|
|
163
|
+
if (type === 'MEASURE') return '';
|
|
164
|
+
|
|
165
|
+
const normalized = this.normalizeFilterColumns(filter);
|
|
166
|
+
|
|
167
|
+
if (type === 'VALUES') return this.buildValuesFilter(normalized);
|
|
168
|
+
if (type === 'RANGE') {
|
|
169
|
+
const hasAgg =
|
|
170
|
+
Array.isArray(normalized.aggregationType) && normalized.aggregationType.length > 0;
|
|
171
|
+
if (hasAgg) {
|
|
172
|
+
// if RANGE filter has aggregationType but only checks for blank/not blank,
|
|
173
|
+
// generate a WHERE clause on the base column (non-aggregated).
|
|
174
|
+
if (this.hasOnlyBlankRangeComparisons(normalized)) {
|
|
175
|
+
return this.buildBlankRangeWhere(normalized);
|
|
176
|
+
}
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const adjusted = this.adjustFilterForBlend(normalized);
|
|
181
|
+
switch (type) {
|
|
182
|
+
case 'RANGE':
|
|
183
|
+
return SharedFilterBuilder.buildRangeFilter(adjusted);
|
|
184
|
+
case 'DATE':
|
|
185
|
+
case 'DATE_RANGE':
|
|
186
|
+
return SharedFilterBuilder.buildDateFilter(adjusted);
|
|
187
|
+
case 'RANKING':
|
|
188
|
+
return '';
|
|
189
|
+
case 'SEARCH':
|
|
190
|
+
return SharedFilterBuilder.buildSearchFilter(adjusted);
|
|
191
|
+
case 'BLANK':
|
|
192
|
+
return SharedFilterBuilder.buildBlankFilter(adjusted);
|
|
193
|
+
case 'TUPLE':
|
|
194
|
+
return SharedFilterBuilder.buildTupleFilter(adjusted);
|
|
195
|
+
case 'RELATIVE_PERIOD':
|
|
196
|
+
return SharedFilterBuilder.buildRelativePeriodFilter(adjusted);
|
|
197
|
+
case 'DATE_HIERARCHY':
|
|
198
|
+
return SharedFilterBuilder.buildDateHierarchyFilter(adjusted);
|
|
199
|
+
case 'FIELD_PARAMETER':
|
|
200
|
+
return SharedFilterBuilder.buildFieldParameterFilter(adjusted);
|
|
201
|
+
default:
|
|
202
|
+
return '';
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private normalizeFilterColumns(filter: FilterConfig): FilterConfig {
|
|
207
|
+
const columnIds = filter.columnIds || [];
|
|
208
|
+
const source = BaseUtilities.getSource(this.options);
|
|
209
|
+
const normalizedColumnNames = columnIds.length
|
|
210
|
+
? columnIds.map((id) => BaseUtilities.extractColumnIdFromHierarchy(id))
|
|
211
|
+
: filter.columnNames || [];
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
...filter,
|
|
215
|
+
columnNames: normalizedColumnNames,
|
|
216
|
+
columnIds: source === SOURCE_TYPES.BLEND ? filter.columnIds : [],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private isBlankOperator(op?: string): boolean {
|
|
221
|
+
if (!op) return false;
|
|
222
|
+
const canonical = op.toUpperCase().replace(/[^A-Z_]+/g, '_');
|
|
223
|
+
return canonical === 'IS_BLANK' || canonical === 'IS_NOT_BLANK';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private hasOnlyBlankRangeComparisons(filter: FilterConfig): boolean {
|
|
227
|
+
if (!filter?.rangeFilter?.length) return false;
|
|
228
|
+
let sawBlank = false;
|
|
229
|
+
for (const r of filter.rangeFilter) {
|
|
230
|
+
const parts = [r.fromCondition, r.toCondition, r.operator].filter(Boolean) as string[];
|
|
231
|
+
if (parts.length === 0) continue;
|
|
232
|
+
const hasNonBlank = parts.some((p) => !this.isBlankOperator(p));
|
|
233
|
+
if (hasNonBlank) return false;
|
|
234
|
+
const hasBlank = parts.some((p) => this.isBlankOperator(p));
|
|
235
|
+
if (hasBlank) sawBlank = true;
|
|
236
|
+
}
|
|
237
|
+
return sawBlank;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private buildColumnReferenceForWhere(filter: FilterConfig): string {
|
|
241
|
+
const source = BaseUtilities.getSource(this.options);
|
|
242
|
+
const idFromPayload = filter.columnIds?.[0];
|
|
243
|
+
const actualIdFromName =
|
|
244
|
+
(filter.tableNames?.[0] || '') && (filter.columnNames?.[0] || '')
|
|
245
|
+
? `${filter.tableNames?.[0]}[${filter.columnNames?.[0]}]`
|
|
246
|
+
: filter.columnNames?.[0] || '';
|
|
247
|
+
const actualColumnId = BaseUtilities.extractColumnIdFromHierarchy(
|
|
248
|
+
idFromPayload || actualIdFromName,
|
|
249
|
+
);
|
|
250
|
+
const idForDb =
|
|
251
|
+
source === SOURCE_TYPES.BLEND ? idFromPayload || actualColumnId : actualColumnId;
|
|
252
|
+
|
|
253
|
+
const useDot = BaseUtilities.shouldUseDotNotation(this.options);
|
|
254
|
+
const tableName =
|
|
255
|
+
filter.tableNames?.[0] || BaseUtilities.getDefaultTableNameFromOptions(this.options);
|
|
256
|
+
|
|
257
|
+
if (useDot && tableName) {
|
|
258
|
+
return BaseUtilities.buildColumnReference(tableName, idForDb);
|
|
259
|
+
}
|
|
260
|
+
return `"${idForDb}"`;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private buildBlankRangeWhere(filter: FilterConfig): string {
|
|
264
|
+
if (!filter.rangeFilter?.length) return '';
|
|
265
|
+
const columnRef = this.buildColumnReferenceForWhere(filter);
|
|
266
|
+
|
|
267
|
+
const rangeConditions: string[] = [];
|
|
268
|
+
for (const r of filter.rangeFilter) {
|
|
269
|
+
const parts: string[] = [];
|
|
270
|
+
if (this.isBlankOperator(r.fromCondition)) {
|
|
271
|
+
parts.push(
|
|
272
|
+
`${columnRef} ${r.fromCondition?.toUpperCase() === 'IS_NOT_BLANK' ? 'IS NOT NULL' : 'IS NULL'}`,
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
if (this.isBlankOperator(r.toCondition)) {
|
|
276
|
+
parts.push(
|
|
277
|
+
`${columnRef} ${r.toCondition?.toUpperCase() === 'IS_NOT_BLANK' ? 'IS NOT NULL' : 'IS NULL'}`,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
if (parts.length > 0) {
|
|
281
|
+
const joiner = (r.logicalOperator || 'AND').toUpperCase() === 'OR' ? 'OR' : 'AND';
|
|
282
|
+
rangeConditions.push(parts.length === 1 ? parts[0] : `(${parts.join(` ${joiner} `)})`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const topJoiner = (filter.logicalOperator as 'AND' | 'OR') || 'AND';
|
|
286
|
+
return BaseUtilities.buildWhereCondition(rangeConditions, topJoiner);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private isComplexFilter(filter: FilterConfig): boolean {
|
|
290
|
+
return Boolean(
|
|
291
|
+
filter.filterType === 'TUPLE' ||
|
|
292
|
+
filter.filterType === 'RANKING' ||
|
|
293
|
+
filter.filterType === 'SEARCH' ||
|
|
294
|
+
filter.filterType === 'BLANK' ||
|
|
295
|
+
filter.filterType === 'RELATIVE_PERIOD' ||
|
|
296
|
+
filter.filterType === 'DATE_HIERARCHY' ||
|
|
297
|
+
filter.filterType === 'FIELD_PARAMETER' ||
|
|
298
|
+
filter.isCrossHighlight ||
|
|
299
|
+
(filter.filterType === 'RANGE' && filter.rangeFilter && filter.rangeFilter.length > 1) ||
|
|
300
|
+
(filter.filterType === 'VALUES' && filter.valuesFilter && filter.valuesFilter.length > 10),
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
protected hasComplexFilters(): boolean {
|
|
305
|
+
return Boolean(
|
|
306
|
+
this.options.superFilters?.children?.some(
|
|
307
|
+
(child) => child.filters && this.isComplexFilter(child.filters),
|
|
308
|
+
),
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
protected checkRankingFilters(): void {
|
|
313
|
+
if (!this.options.superFilters?.children) return;
|
|
314
|
+
|
|
315
|
+
const hasRankingFilter = this.options.superFilters.children.some(
|
|
316
|
+
(child) =>
|
|
317
|
+
Array.isArray(child.filters) &&
|
|
318
|
+
child.filters.some((filter: FilterConfig) => filter.filterType === 'RANKING'),
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
if (hasRankingFilter && !this.options.isRankingFilterIncluded) {
|
|
322
|
+
this.options.isRankingFilterIncluded = true;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private buildOrGroupCTE(): string {
|
|
327
|
+
const sf = this.options.superFilters;
|
|
328
|
+
if (!sf || sf.condition?.toUpperCase() !== 'OR' || !sf.children?.length) {
|
|
329
|
+
return '';
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const dims = [
|
|
333
|
+
...BaseUtilities.buildDimensionReference(this.options.rows, this.options),
|
|
334
|
+
...BaseUtilities.buildDimensionReference(this.options.columns, this.options),
|
|
335
|
+
];
|
|
336
|
+
if (dims.length === 0) return '';
|
|
337
|
+
|
|
338
|
+
const tableName = BaseUtilities.formatTableNameForDb(
|
|
339
|
+
BaseUtilities.getDefaultTableNameFromOptions(this.options),
|
|
340
|
+
this.options.databaseDetails?.databaseType as string,
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
const selectCols = dims.map((expr, idx) => `${expr} AS __or_dim${idx + 1}`).join(', ');
|
|
344
|
+
|
|
345
|
+
const parts: string[] = [];
|
|
346
|
+
sf.children.forEach((child) => {
|
|
347
|
+
const cond = this.buildSuperFilterChild(child);
|
|
348
|
+
if (cond && cond.trim()) {
|
|
349
|
+
parts.push(`SELECT DISTINCT ${selectCols} FROM ${tableName} WHERE ${cond}`);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
if (parts.length === 0) return '';
|
|
354
|
+
return `__or_group AS (\n${parts.join('\nUNION\n')}\n)`;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
buildOrGroupExistsClause(): string {
|
|
358
|
+
const sf = this.options.superFilters;
|
|
359
|
+
if (!sf || sf.condition?.toUpperCase() !== 'OR' || !sf.children?.length) {
|
|
360
|
+
return '';
|
|
361
|
+
}
|
|
362
|
+
const dims = [
|
|
363
|
+
...BaseUtilities.buildDimensionReference(this.options.rows, this.options),
|
|
364
|
+
...BaseUtilities.buildDimensionReference(this.options.columns, this.options),
|
|
365
|
+
];
|
|
366
|
+
if (dims.length === 0) return '';
|
|
367
|
+
const comparisons = dims.map((expr, idx) => `${expr} = g.__or_dim${idx + 1}`).join(' AND ');
|
|
368
|
+
return `EXISTS (SELECT 1 FROM __or_group g WHERE ${comparisons})`;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export abstract class QueryBuilderError extends Error {
|
|
2
|
+
abstract readonly code: string;
|
|
3
|
+
|
|
4
|
+
constructor(
|
|
5
|
+
message: string,
|
|
6
|
+
public readonly details?: Record<string, unknown>,
|
|
7
|
+
) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = this.constructor.name;
|
|
10
|
+
Error.captureStackTrace(this, this.constructor);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class InvalidConfigurationError extends QueryBuilderError {
|
|
15
|
+
readonly code = 'INVALID_CONFIGURATION';
|
|
16
|
+
|
|
17
|
+
constructor(message: string, details?: Record<string, unknown>) {
|
|
18
|
+
super(`Configuration Error: ${message}`, details);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class FilterValidationError extends QueryBuilderError {
|
|
23
|
+
readonly code = 'FILTER_VALIDATION_ERROR';
|
|
24
|
+
|
|
25
|
+
constructor(filterType: string, message: string, details?: Record<string, unknown>) {
|
|
26
|
+
super(`Filter Validation Error (${filterType}): ${message}`, details);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class MeasureValidationError extends QueryBuilderError {
|
|
31
|
+
readonly code = 'MEASURE_VALIDATION_ERROR';
|
|
32
|
+
|
|
33
|
+
constructor(measureName: string, message: string, details?: Record<string, unknown>) {
|
|
34
|
+
super(`Measure Validation Error (${measureName}): ${message}`, details);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class PaginationError extends QueryBuilderError {
|
|
39
|
+
readonly code = 'PAGINATION_ERROR';
|
|
40
|
+
|
|
41
|
+
constructor(command: string, message: string, details?: Record<string, unknown>) {
|
|
42
|
+
super(`Pagination Error (${command}): ${message}`, details);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class QueryGenerationError extends QueryBuilderError {
|
|
47
|
+
readonly code = 'QUERY_GENERATION_ERROR';
|
|
48
|
+
|
|
49
|
+
constructor(message: string, details?: Record<string, unknown>) {
|
|
50
|
+
super(`Query Generation Error: ${message}`, details);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class TableNotFoundError extends QueryBuilderError {
|
|
55
|
+
readonly code = 'TABLE_NOT_FOUND';
|
|
56
|
+
|
|
57
|
+
constructor(tableName?: string, details?: Record<string, unknown>) {
|
|
58
|
+
super(
|
|
59
|
+
tableName
|
|
60
|
+
? `Table not found: ${tableName}`
|
|
61
|
+
: 'No table name found in configuration. Please specify tableName in rows, columns, or values.',
|
|
62
|
+
details,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './IDatabaseQueryBuilder';
|