@hypequery/clickhouse 0.2.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/README-CLI.md +123 -0
- package/README.md +276 -0
- package/dist/cli/bin.js +151 -0
- package/dist/cli/generate-types.d.ts +5 -0
- package/dist/cli/generate-types.js +91 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +2 -0
- package/dist/core/connection.d.ts.map +1 -0
- package/dist/core/connection.js +34 -0
- package/dist/core/cross-filter.d.ts.map +1 -0
- package/dist/core/cross-filter.js +218 -0
- package/dist/core/features/aggregations.d.ts.map +1 -0
- package/dist/core/features/aggregations.js +35 -0
- package/dist/core/features/analytics.d.ts.map +1 -0
- package/dist/core/features/analytics.js +35 -0
- package/dist/core/features/executor.d.ts.map +1 -0
- package/dist/core/features/executor.js +136 -0
- package/dist/core/features/filtering.d.ts.map +1 -0
- package/dist/core/features/filtering.js +30 -0
- package/dist/core/features/joins.d.ts.map +1 -0
- package/dist/core/features/joins.js +16 -0
- package/dist/core/features/pagination.d.ts.map +1 -0
- package/dist/core/features/pagination.js +190 -0
- package/dist/core/features/query-modifiers.d.ts.map +1 -0
- package/dist/core/features/query-modifiers.js +50 -0
- package/dist/core/formatters/sql-formatter.d.ts.map +1 -0
- package/dist/core/formatters/sql-formatter.js +69 -0
- package/dist/core/join-relationships.d.ts.map +1 -0
- package/dist/core/join-relationships.js +56 -0
- package/dist/core/query-builder.d.ts.map +1 -0
- package/dist/core/query-builder.js +372 -0
- package/dist/core/tests/index.d.ts.map +1 -0
- package/dist/core/tests/index.js +1 -0
- package/dist/core/tests/integration/setup.d.ts.map +1 -0
- package/dist/core/tests/integration/setup.js +274 -0
- package/dist/core/tests/test-utils.d.ts.map +1 -0
- package/dist/core/tests/test-utils.js +32 -0
- package/dist/core/utils/logger.d.ts.map +1 -0
- package/dist/core/utils/logger.js +98 -0
- package/dist/core/utils/sql-expressions.d.ts.map +1 -0
- package/dist/core/utils/sql-expressions.js +73 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +29 -0
- package/dist/core/validators/filter-validator.d.ts.map +1 -0
- package/dist/core/validators/filter-validator.js +19 -0
- package/dist/core/validators/value-validator.d.ts.map +1 -0
- package/dist/core/validators/value-validator.js +47 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/types/base.d.ts.map +1 -0
- package/dist/types/base.js +1 -0
- package/dist/types/clickhouse-types.d.ts.map +1 -0
- package/dist/types/clickhouse-types.js +1 -0
- package/dist/types/filters.d.ts.map +1 -0
- package/dist/types/filters.js +1 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/package.json +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-filter.d.ts","sourceRoot":"","sources":["../../src/core/cross-filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { FilterValidator } from './validators/filter-validator';
|
|
2
|
+
export const DateRange = {
|
|
3
|
+
TODAY: 'today',
|
|
4
|
+
YESTERDAY: 'yesterday',
|
|
5
|
+
LAST_7_DAYS: 'last_7_days',
|
|
6
|
+
LAST_30_DAYS: 'last_30_days',
|
|
7
|
+
THIS_MONTH: 'this_month',
|
|
8
|
+
LAST_MONTH: 'last_month',
|
|
9
|
+
THIS_QUARTER: 'this_quarter',
|
|
10
|
+
YEAR_TO_DATE: 'year_to_date'
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A type-safe filter builder supporting both simple conditions and complex nested groups.
|
|
14
|
+
* @template Schema - The full database schema type
|
|
15
|
+
* @template TableName - The specific table being filtered
|
|
16
|
+
*/
|
|
17
|
+
export class CrossFilter {
|
|
18
|
+
// Optionally pass a schema to get full type-validation.
|
|
19
|
+
constructor(schema) {
|
|
20
|
+
this.schema = schema;
|
|
21
|
+
this.rootGroup = { operator: 'AND', conditions: [] };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Adds a single filter condition to the root group with an implicit AND conjunction.
|
|
25
|
+
* Performs type-safe validation if a schema is provided.
|
|
26
|
+
*/
|
|
27
|
+
add(condition) {
|
|
28
|
+
if (this.schema) {
|
|
29
|
+
const columnType = this.getColumnType(String(condition.column));
|
|
30
|
+
this.validateValueType(columnType, condition.value, String(condition.column), condition.operator);
|
|
31
|
+
}
|
|
32
|
+
// Convert Date objects to ISO strings for ClickHouse
|
|
33
|
+
let value = condition.value;
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
value = value.map(v => v instanceof Date ? v.toISOString() : v);
|
|
36
|
+
}
|
|
37
|
+
else if (value instanceof Date) {
|
|
38
|
+
value = value.toISOString();
|
|
39
|
+
}
|
|
40
|
+
this.rootGroup.conditions.push({
|
|
41
|
+
...condition,
|
|
42
|
+
value
|
|
43
|
+
});
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Adds multiple filter conditions to the root group.
|
|
48
|
+
*/
|
|
49
|
+
addMultiple(conditions) {
|
|
50
|
+
if (this.schema) {
|
|
51
|
+
this.validateGroup(conditions);
|
|
52
|
+
}
|
|
53
|
+
this.rootGroup.conditions.push(...conditions);
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Adds a nested group of filter conditions to the root group using the specified logical operator.
|
|
58
|
+
* @param groupConditions - Array of filter conditions or nested groups to be grouped together.
|
|
59
|
+
* @param operator - Logical operator ('AND' or 'OR') to combine the conditions in the group.
|
|
60
|
+
*/
|
|
61
|
+
addGroup(groupConditions, operator) {
|
|
62
|
+
if (this.schema) {
|
|
63
|
+
this.validateGroup(groupConditions);
|
|
64
|
+
}
|
|
65
|
+
const group = {
|
|
66
|
+
operator,
|
|
67
|
+
conditions: groupConditions
|
|
68
|
+
};
|
|
69
|
+
this.rootGroup.conditions.push(group);
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns the current filter tree representing all conditions and groups.
|
|
74
|
+
*/
|
|
75
|
+
getConditions() {
|
|
76
|
+
return this.rootGroup;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Looks up a column's type from the schema.
|
|
80
|
+
* Defaults to 'String' if no schema is provided.
|
|
81
|
+
* @param column - The column name as a string.
|
|
82
|
+
*/
|
|
83
|
+
getColumnType(column) {
|
|
84
|
+
if (!this.schema) {
|
|
85
|
+
return 'String';
|
|
86
|
+
}
|
|
87
|
+
for (const table in this.schema) {
|
|
88
|
+
const tableSchema = this.schema[table];
|
|
89
|
+
if (column in tableSchema) {
|
|
90
|
+
return tableSchema[column];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
throw new Error(`Column '${column}' not found in schema`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validates the value of a filter condition against its expected column type.
|
|
97
|
+
*/
|
|
98
|
+
validateValueType(columnType, value, columnName, operator) {
|
|
99
|
+
FilterValidator.validateFilterCondition({ column: columnName, operator, value }, columnType, { allowNull: true } // CrossFilter allows null values
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Recursively validates an array of filter conditions and nested groups.
|
|
104
|
+
*/
|
|
105
|
+
validateGroup(conditions) {
|
|
106
|
+
for (const condition of conditions) {
|
|
107
|
+
if (this.isGroup(condition)) {
|
|
108
|
+
// Recursively validate nested groups
|
|
109
|
+
this.validateGroup(condition.conditions);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const columnType = this.getColumnType(String(condition.column));
|
|
113
|
+
this.validateValueType(columnType, condition.value, String(condition.column), condition.operator);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Type guard to check if an item is a FilterGroup.
|
|
119
|
+
*/
|
|
120
|
+
isGroup(item) {
|
|
121
|
+
return typeof item.conditions !== 'undefined';
|
|
122
|
+
}
|
|
123
|
+
addDateCondition(column, value) {
|
|
124
|
+
this.rootGroup.conditions.push({
|
|
125
|
+
column,
|
|
126
|
+
operator: 'between',
|
|
127
|
+
value: [value[0].toISOString(), value[1].toISOString()]
|
|
128
|
+
});
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
addDateRange(column, range) {
|
|
132
|
+
const now = new Date();
|
|
133
|
+
let start;
|
|
134
|
+
let end;
|
|
135
|
+
switch (range) {
|
|
136
|
+
case 'today':
|
|
137
|
+
start = new Date(now.setHours(0, 0, 0, 0));
|
|
138
|
+
end = new Date(now.setHours(23, 59, 59, 999));
|
|
139
|
+
break;
|
|
140
|
+
case 'yesterday':
|
|
141
|
+
start = new Date(now.setDate(now.getDate() - 1));
|
|
142
|
+
start.setHours(0, 0, 0, 0);
|
|
143
|
+
end = new Date(start);
|
|
144
|
+
end.setHours(23, 59, 59, 999);
|
|
145
|
+
break;
|
|
146
|
+
case 'last_7_days':
|
|
147
|
+
end = new Date(now);
|
|
148
|
+
start = new Date(now.setDate(now.getDate() - 7));
|
|
149
|
+
break;
|
|
150
|
+
case 'last_30_days':
|
|
151
|
+
end = new Date(now);
|
|
152
|
+
start = new Date(now.setDate(now.getDate() - 30));
|
|
153
|
+
break;
|
|
154
|
+
case 'this_month':
|
|
155
|
+
start = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
156
|
+
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
|
157
|
+
break;
|
|
158
|
+
case 'last_month':
|
|
159
|
+
start = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
|
160
|
+
end = new Date(now.getFullYear(), now.getMonth(), 0);
|
|
161
|
+
break;
|
|
162
|
+
case 'this_quarter':
|
|
163
|
+
const quarter = Math.floor(now.getMonth() / 3);
|
|
164
|
+
start = new Date(now.getFullYear(), quarter * 3, 1);
|
|
165
|
+
end = new Date(now.getFullYear(), (quarter + 1) * 3, 0);
|
|
166
|
+
break;
|
|
167
|
+
case 'year_to_date':
|
|
168
|
+
start = new Date(now.getFullYear(), 0, 1);
|
|
169
|
+
end = new Date(now);
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
throw new Error(`Unsupported date range: ${range}`);
|
|
173
|
+
}
|
|
174
|
+
return this.addDateCondition(column, [start, end]);
|
|
175
|
+
}
|
|
176
|
+
lastNDays(column, days) {
|
|
177
|
+
const end = new Date();
|
|
178
|
+
const start = new Date();
|
|
179
|
+
start.setDate(start.getDate() - days);
|
|
180
|
+
return this.addDateCondition(column, [start, end]);
|
|
181
|
+
}
|
|
182
|
+
addComparisonPeriod(column, currentRange) {
|
|
183
|
+
const periodLength = currentRange[1].getTime() - currentRange[0].getTime();
|
|
184
|
+
const previousStart = new Date(currentRange[0].getTime() - periodLength);
|
|
185
|
+
const previousEnd = new Date(currentRange[1].getTime() - periodLength);
|
|
186
|
+
return this.addDateCondition(column, [previousStart, previousEnd]);
|
|
187
|
+
}
|
|
188
|
+
addYearOverYear(column, currentRange) {
|
|
189
|
+
const previousStart = new Date(currentRange[0]);
|
|
190
|
+
previousStart.setFullYear(previousStart.getFullYear() - 1);
|
|
191
|
+
const previousEnd = new Date(currentRange[1]);
|
|
192
|
+
previousEnd.setFullYear(previousEnd.getFullYear() - 1);
|
|
193
|
+
return this.addDateCondition(column, [previousStart, previousEnd]);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Creates a filter for top N records by a value column
|
|
197
|
+
* @param valueColumn - The column to filter and order by
|
|
198
|
+
* @param n - Number of records to return
|
|
199
|
+
* @param orderBy - Sort direction, defaults to 'desc'
|
|
200
|
+
*/
|
|
201
|
+
topN(valueColumn, n, orderBy = 'desc') {
|
|
202
|
+
this.add({
|
|
203
|
+
column: valueColumn,
|
|
204
|
+
operator: 'gt',
|
|
205
|
+
value: 0
|
|
206
|
+
});
|
|
207
|
+
// Store limit and order information in the root group's metadata
|
|
208
|
+
this.rootGroup = {
|
|
209
|
+
...this.rootGroup,
|
|
210
|
+
limit: n,
|
|
211
|
+
orderBy: {
|
|
212
|
+
column: valueColumn,
|
|
213
|
+
direction: orderBy.toUpperCase()
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
return this;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregations.d.ts","sourceRoot":"","sources":["../../../src/core/features/aggregations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,qBAAa,kBAAkB,CAC7B,MAAM,SAAS;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAA;CAAE,EAC5E,CAAC,EACD,SAAS,SAAS,OAAO,GAAG,KAAK,EACjC,YAAY,GAAG,EAAE,EACjB,SAAS,GAAG,CAAC;IAED,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC;IAExF,OAAO,CAAC,iBAAiB;IAsBzB,GAAG,CAAC,MAAM,SAAS,MAAM,SAAS,EAAE,KAAK,SAAS,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,MAAM,EACjF,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,KAAK;;;;;;;;;;;;;;;;;;IASf,KAAK,CAAC,MAAM,SAAS,MAAM,SAAS,EAAE,KAAK,SAAS,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,QAAQ,EACrF,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,KAAK;;;;;;;;;;;;;;;;;;IASf,GAAG,CAAC,MAAM,SAAS,MAAM,SAAS,EAAE,KAAK,SAAS,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,MAAM,EACjF,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,KAAK;;;;;;;;;;;;;;;;;;IASf,GAAG,CAAC,MAAM,SAAS,MAAM,SAAS,EAAE,KAAK,SAAS,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,MAAM,EACjF,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,KAAK;;;;;;;;;;;;;;;;;;IASf,GAAG,CAAC,MAAM,SAAS,MAAM,SAAS,EAAE,KAAK,SAAS,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,MAAM,EACjF,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,KAAK;;;;;;;;;;;;;;;;;;CAQhB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export class AggregationFeature {
|
|
2
|
+
constructor(builder) {
|
|
3
|
+
this.builder = builder;
|
|
4
|
+
}
|
|
5
|
+
createAggregation(column, fn, alias) {
|
|
6
|
+
const aggregationSQL = `${fn}(${String(column)}) AS ${alias}`;
|
|
7
|
+
const config = this.builder.getConfig();
|
|
8
|
+
if (config.select) {
|
|
9
|
+
return {
|
|
10
|
+
...config,
|
|
11
|
+
select: [...(config.select || []).map(String), aggregationSQL],
|
|
12
|
+
groupBy: (config.select || []).map(String).filter(col => !col.includes(' AS '))
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
...config,
|
|
17
|
+
select: [aggregationSQL]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
sum(column, alias) {
|
|
21
|
+
return this.createAggregation(column, 'SUM', alias || `${String(column)}_sum`);
|
|
22
|
+
}
|
|
23
|
+
count(column, alias) {
|
|
24
|
+
return this.createAggregation(column, 'COUNT', alias || `${String(column)}_count`);
|
|
25
|
+
}
|
|
26
|
+
avg(column, alias) {
|
|
27
|
+
return this.createAggregation(column, 'AVG', alias || `${String(column)}_avg`);
|
|
28
|
+
}
|
|
29
|
+
min(column, alias) {
|
|
30
|
+
return this.createAggregation(column, 'MIN', alias || `${String(column)}_min`);
|
|
31
|
+
}
|
|
32
|
+
max(column, alias) {
|
|
33
|
+
return this.createAggregation(column, 'MAX', alias || `${String(column)}_max`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../../src/core/features/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,qBAAa,gBAAgB,CAC3B,MAAM,SAAS;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAA;CAAE,EAC5E,CAAC,EACD,SAAS,SAAS,OAAO,GAAG,KAAK,EACjC,YAAY,GAAG,EAAE,EACjB,SAAS,GAAG,CAAC;IAED,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC;IAExF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,MAAM;;;;;;;;;;;;;;;;;;IAS/D,eAAe,CACb,MAAM,EAAE,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,EACrC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,GAAG,iBAAiB,GAAG,eAAe,GAAG,cAAc,GAAG,eAAe,GAAG,gBAAgB,GAAG,kBAAkB,GAAG,eAAe;;;;;;;;;;;;;;;;;;IAiBhK,WAAW,CAAC,IAAI,EAAE,kBAAkB;;;;;;;;;;;;;;;;;;CAQrC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export class AnalyticsFeature {
|
|
2
|
+
constructor(builder) {
|
|
3
|
+
this.builder = builder;
|
|
4
|
+
}
|
|
5
|
+
addCTE(alias, subquery) {
|
|
6
|
+
const config = this.builder.getConfig();
|
|
7
|
+
const cte = typeof subquery === 'string' ? subquery : subquery.toSQL();
|
|
8
|
+
return {
|
|
9
|
+
...config,
|
|
10
|
+
ctes: [...(config.ctes || []), `${alias} AS (${cte})`]
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
addTimeInterval(column, interval, method) {
|
|
14
|
+
const config = this.builder.getConfig();
|
|
15
|
+
const groupBy = config.groupBy || [];
|
|
16
|
+
if (method === 'toStartOfInterval') {
|
|
17
|
+
groupBy.push(`${method}(${String(column)}, INTERVAL ${interval})`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
groupBy.push(`${method}(${String(column)})`);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
...config,
|
|
24
|
+
groupBy
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
addSettings(opts) {
|
|
28
|
+
const config = this.builder.getConfig();
|
|
29
|
+
const settingsFragments = Object.entries(opts).map(([key, value]) => `${key}=${value}`);
|
|
30
|
+
return {
|
|
31
|
+
...config,
|
|
32
|
+
settings: settingsFragments.join(', ')
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/core/features/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC,qBAAa,eAAe,CAC1B,MAAM,SAAS;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAA;CAAE,EAC5E,CAAC,EACD,SAAS,SAAS,OAAO,GAAG,KAAK,EACjC,YAAY,GAAG,EAAE,EACjB,SAAS,GAAG,CAAC;IAED,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC;IAExF,eAAe,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,GAAG,EAAE,CAAA;KAAE;IAOrD,KAAK,IAAI,MAAM;IAKT,OAAO,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAgDvB,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IA+C5C,OAAO,CAAC,sBAAsB;CA0C/B"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { ClickHouseConnection } from '../connection';
|
|
2
|
+
import { substituteParameters } from '../utils';
|
|
3
|
+
import { logger } from '../utils/logger';
|
|
4
|
+
export class ExecutorFeature {
|
|
5
|
+
constructor(builder) {
|
|
6
|
+
this.builder = builder;
|
|
7
|
+
}
|
|
8
|
+
toSQLWithParams() {
|
|
9
|
+
const sql = this.toSQLWithoutParameters();
|
|
10
|
+
const config = this.builder.getConfig();
|
|
11
|
+
const parameters = config.parameters || [];
|
|
12
|
+
return { sql, parameters };
|
|
13
|
+
}
|
|
14
|
+
toSQL() {
|
|
15
|
+
const { sql, parameters } = this.toSQLWithParams();
|
|
16
|
+
return substituteParameters(sql, parameters);
|
|
17
|
+
}
|
|
18
|
+
async execute() {
|
|
19
|
+
const client = ClickHouseConnection.getClient();
|
|
20
|
+
const { sql, parameters } = this.toSQLWithParams();
|
|
21
|
+
const finalSQL = substituteParameters(sql, parameters);
|
|
22
|
+
const startTime = Date.now();
|
|
23
|
+
logger.logQuery({
|
|
24
|
+
query: finalSQL,
|
|
25
|
+
parameters,
|
|
26
|
+
startTime,
|
|
27
|
+
status: 'started'
|
|
28
|
+
});
|
|
29
|
+
try {
|
|
30
|
+
const result = await client.query({
|
|
31
|
+
query: finalSQL,
|
|
32
|
+
format: 'JSONEachRow'
|
|
33
|
+
});
|
|
34
|
+
const rows = await result.json();
|
|
35
|
+
const endTime = Date.now();
|
|
36
|
+
logger.logQuery({
|
|
37
|
+
query: finalSQL,
|
|
38
|
+
parameters,
|
|
39
|
+
startTime,
|
|
40
|
+
endTime,
|
|
41
|
+
duration: endTime - startTime,
|
|
42
|
+
status: 'completed',
|
|
43
|
+
rowCount: rows.length
|
|
44
|
+
});
|
|
45
|
+
return rows;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const endTime = Date.now();
|
|
49
|
+
logger.logQuery({
|
|
50
|
+
query: finalSQL,
|
|
51
|
+
parameters,
|
|
52
|
+
startTime,
|
|
53
|
+
endTime,
|
|
54
|
+
duration: endTime - startTime,
|
|
55
|
+
status: 'error',
|
|
56
|
+
error: error
|
|
57
|
+
});
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async stream() {
|
|
62
|
+
const client = ClickHouseConnection.getClient();
|
|
63
|
+
const { sql, parameters } = this.toSQLWithParams();
|
|
64
|
+
const finalSQL = substituteParameters(sql, parameters);
|
|
65
|
+
const startTime = Date.now();
|
|
66
|
+
logger.logQuery({
|
|
67
|
+
query: finalSQL,
|
|
68
|
+
parameters,
|
|
69
|
+
startTime,
|
|
70
|
+
status: 'started'
|
|
71
|
+
});
|
|
72
|
+
try {
|
|
73
|
+
const result = await client.query({
|
|
74
|
+
query: finalSQL,
|
|
75
|
+
format: 'JSONEachRow'
|
|
76
|
+
});
|
|
77
|
+
const stream = result.stream();
|
|
78
|
+
const endTime = Date.now();
|
|
79
|
+
logger.logQuery({
|
|
80
|
+
query: finalSQL,
|
|
81
|
+
parameters,
|
|
82
|
+
startTime,
|
|
83
|
+
endTime,
|
|
84
|
+
duration: endTime - startTime,
|
|
85
|
+
status: 'completed'
|
|
86
|
+
});
|
|
87
|
+
return stream;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const endTime = Date.now();
|
|
91
|
+
logger.logQuery({
|
|
92
|
+
query: finalSQL,
|
|
93
|
+
parameters,
|
|
94
|
+
startTime,
|
|
95
|
+
endTime,
|
|
96
|
+
duration: endTime - startTime,
|
|
97
|
+
status: 'error',
|
|
98
|
+
error: error
|
|
99
|
+
});
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
toSQLWithoutParameters() {
|
|
104
|
+
const config = this.builder.getConfig();
|
|
105
|
+
const formatter = this.builder.getFormatter();
|
|
106
|
+
const parts = [];
|
|
107
|
+
if (config.ctes?.length) {
|
|
108
|
+
parts.push(`WITH ${config.ctes.join(', ')}`);
|
|
109
|
+
}
|
|
110
|
+
parts.push(`SELECT ${formatter.formatSelect(config)}`);
|
|
111
|
+
parts.push(`FROM ${this.builder.getTableName()}`);
|
|
112
|
+
if (config.joins?.length) {
|
|
113
|
+
parts.push(formatter.formatJoins(config));
|
|
114
|
+
}
|
|
115
|
+
if (config.where?.length) {
|
|
116
|
+
parts.push(`WHERE ${formatter.formatWhere(config)}`);
|
|
117
|
+
}
|
|
118
|
+
if (config.groupBy?.length) {
|
|
119
|
+
parts.push(`GROUP BY ${formatter.formatGroupBy(config)}`);
|
|
120
|
+
}
|
|
121
|
+
if (config.having?.length) {
|
|
122
|
+
parts.push(`HAVING ${config.having.join(' AND ')}`);
|
|
123
|
+
}
|
|
124
|
+
if (config.orderBy?.length) {
|
|
125
|
+
const orderBy = config.orderBy
|
|
126
|
+
.map(({ column, direction }) => `${String(column)} ${direction}`.trim())
|
|
127
|
+
.join(', ');
|
|
128
|
+
parts.push(`ORDER BY ${orderBy}`);
|
|
129
|
+
}
|
|
130
|
+
if (config.limit) {
|
|
131
|
+
const offsetClause = config.offset ? `OFFSET ${config.offset}` : '';
|
|
132
|
+
parts.push(`LIMIT ${config.limit} ${offsetClause}`);
|
|
133
|
+
}
|
|
134
|
+
return parts.join(' ').trim();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filtering.d.ts","sourceRoot":"","sources":["../../../src/core/features/filtering.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtE,qBAAa,gBAAgB,CAC3B,MAAM,SAAS;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAA;CAAE,EAC5E,CAAC,EACD,SAAS,SAAS,OAAO,GAAG,KAAK,EACjC,YAAY,GAAG,EAAE,EACjB,SAAS,GAAG,CAAC;IAED,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC;IAExF,YAAY,CAAC,CAAC,SAAS,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,EAC1D,WAAW,EAAE,KAAK,GAAG,IAAI,EACzB,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,GAAG;;;;;;;;;;;;;;;;;;CA6Bb"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class FilteringFeature {
|
|
2
|
+
constructor(builder) {
|
|
3
|
+
this.builder = builder;
|
|
4
|
+
}
|
|
5
|
+
addCondition(conjunction, column, operator, value) {
|
|
6
|
+
const config = this.builder.getConfig();
|
|
7
|
+
const where = config.where || [];
|
|
8
|
+
const parameters = config.parameters || [];
|
|
9
|
+
where.push({
|
|
10
|
+
column: String(column),
|
|
11
|
+
operator,
|
|
12
|
+
value,
|
|
13
|
+
conjunction
|
|
14
|
+
});
|
|
15
|
+
if (operator === 'in' || operator === 'notIn') {
|
|
16
|
+
parameters.push(...value);
|
|
17
|
+
}
|
|
18
|
+
else if (operator === 'between') {
|
|
19
|
+
parameters.push(value[0], value[1]);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
parameters.push(value);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
...config,
|
|
26
|
+
where,
|
|
27
|
+
parameters
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"joins.d.ts","sourceRoot":"","sources":["../../../src/core/features/joins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEnD,qBAAa,WAAW,CACtB,MAAM,SAAS;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAA;CAAE,EAC5E,CAAC,EACD,SAAS,SAAS,OAAO,GAAG,KAAK,EACjC,YAAY,GAAG,EAAE,EACjB,SAAS,GAAG,CAAC;IAED,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC;IAExF,OAAO,CAAC,SAAS,SAAS,MAAM,MAAM,EACpC,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,MAAM,SAAS,EAC3B,WAAW,EAAE,GAAG,SAAS,GAAG,MAAM,IAAI,MAAM,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,EAAE,EACxE,KAAK,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;CAYjB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export class JoinFeature {
|
|
2
|
+
constructor(builder) {
|
|
3
|
+
this.builder = builder;
|
|
4
|
+
}
|
|
5
|
+
addJoin(type, table, leftColumn, rightColumn, alias) {
|
|
6
|
+
const config = this.builder.getConfig();
|
|
7
|
+
const newConfig = {
|
|
8
|
+
...config,
|
|
9
|
+
joins: [
|
|
10
|
+
...(config.joins || []),
|
|
11
|
+
{ type, table: String(table), leftColumn: String(leftColumn), rightColumn, alias }
|
|
12
|
+
]
|
|
13
|
+
};
|
|
14
|
+
return newConfig;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/core/features/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAyB,MAAM,aAAa,CAAC;AAEpG,qBAAa,iBAAiB,CAC5B,MAAM,SAAS;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAA;CAAE,EAC5E,CAAC,EACD,SAAS,SAAS,OAAO,GAAG,KAAK,EACjC,YAAY,GAAG,EAAE,EACjB,SAAS,GAAG,CAAC;IAKD,OAAO,CAAC,OAAO;IAH3B,OAAO,CAAC,MAAM,CAAC,YAAY,CAAiE;IAC5F,OAAO,CAAC,QAAQ,CAAS;gBAEL,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC;IAQxF,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,WAAW,QAGtB;IAED,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,KAAK,eAAe,QAG1B;IAED,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;IAId,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IA0I1E,OAAO,CAAC,cAAc;IAmBhB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAIvD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;CAkB1E"}
|