@hypequery/clickhouse 0.2.1 → 0.2.3
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/dist/cli/bin.js +128 -36
- package/dist/cli/generate-types.js +101 -12
- package/dist/core/connection.d.ts +136 -0
- package/dist/core/connection.d.ts.map +1 -1
- package/dist/core/connection.js +58 -0
- package/dist/core/cross-filter.d.ts +85 -0
- package/dist/core/features/aggregations.d.ts +102 -0
- package/dist/core/features/analytics.d.ts +66 -0
- package/dist/core/features/cross-filtering.d.ts +31 -0
- package/dist/core/features/cross-filtering.d.ts.map +1 -0
- package/dist/core/features/cross-filtering.js +123 -0
- package/dist/core/features/executor.d.ts +19 -0
- package/dist/core/features/filtering.d.ts +95 -0
- package/dist/core/features/filtering.d.ts.map +1 -1
- package/dist/core/features/filtering.js +59 -1
- package/dist/core/features/joins.d.ts +29 -0
- package/dist/core/features/pagination.d.ts +23 -0
- package/dist/core/features/query-modifiers.d.ts +119 -0
- package/dist/core/formatters/sql-formatter.d.ts +9 -0
- package/dist/core/formatters/sql-formatter.d.ts.map +1 -1
- package/dist/core/formatters/sql-formatter.js +24 -5
- package/dist/core/join-relationships.d.ts +50 -0
- package/dist/core/query-builder.d.ts +222 -0
- package/dist/core/query-builder.d.ts.map +1 -1
- package/dist/core/query-builder.js +38 -6
- package/dist/core/tests/index.d.ts +2 -0
- package/dist/core/tests/integration/pagination-test-tbc.d.ts +2 -0
- package/dist/core/tests/integration/pagination-test-tbc.d.ts.map +1 -0
- package/dist/core/tests/integration/pagination-test-tbc.js +189 -0
- package/dist/core/tests/integration/setup.d.ts +40 -0
- package/dist/core/tests/integration/setup.d.ts.map +1 -1
- package/dist/core/tests/integration/setup.js +278 -237
- package/dist/core/tests/integration/test-config.d.ts +15 -0
- package/dist/core/tests/integration/test-config.d.ts.map +1 -0
- package/dist/core/tests/integration/test-config.js +15 -0
- package/dist/core/tests/test-utils.d.ts +30 -0
- package/dist/core/utils/logger.d.ts +37 -0
- package/dist/core/utils/logger.js +2 -2
- package/dist/core/utils/sql-expressions.d.ts +59 -0
- package/dist/core/utils.d.ts +3 -0
- package/dist/core/validators/filter-validator.d.ts +8 -0
- package/dist/core/validators/value-validator.d.ts +6 -0
- package/dist/formatters/index.d.ts +1 -0
- package/dist/index.d.ts +10 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/dist/types/base.d.ts +77 -0
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/clickhouse-types.d.ts +13 -0
- package/dist/types/filters.d.ts +37 -0
- package/dist/types/index.d.ts +3 -0
- package/package.json +15 -8
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ColumnType, FilterOperator, InferColumnType, OperatorValueMap, FilterConditionInput } from '../types';
|
|
2
|
+
export interface FilterGroup<Schema extends Record<string, Record<string, any>> = any, OriginalT extends Record<string, any> = any> {
|
|
3
|
+
operator: 'AND' | 'OR';
|
|
4
|
+
conditions: Array<FilterConditionInput<any, Schema, OriginalT> | FilterGroup<Schema, OriginalT>>;
|
|
5
|
+
limit?: number;
|
|
6
|
+
orderBy?: {
|
|
7
|
+
column: keyof OriginalT;
|
|
8
|
+
direction: 'ASC' | 'DESC';
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare const DateRange: {
|
|
12
|
+
readonly TODAY: "today";
|
|
13
|
+
readonly YESTERDAY: "yesterday";
|
|
14
|
+
readonly LAST_7_DAYS: "last_7_days";
|
|
15
|
+
readonly LAST_30_DAYS: "last_30_days";
|
|
16
|
+
readonly THIS_MONTH: "this_month";
|
|
17
|
+
readonly LAST_MONTH: "last_month";
|
|
18
|
+
readonly THIS_QUARTER: "this_quarter";
|
|
19
|
+
readonly YEAR_TO_DATE: "year_to_date";
|
|
20
|
+
};
|
|
21
|
+
export type DateRangeType = typeof DateRange[keyof typeof DateRange];
|
|
22
|
+
/**
|
|
23
|
+
* A type-safe filter builder supporting both simple conditions and complex nested groups.
|
|
24
|
+
* @template Schema - The full database schema type
|
|
25
|
+
* @template TableName - The specific table being filtered
|
|
26
|
+
*/
|
|
27
|
+
export declare class CrossFilter<Schema extends {
|
|
28
|
+
[tableName: string]: {
|
|
29
|
+
[columnName: string]: ColumnType;
|
|
30
|
+
};
|
|
31
|
+
} = any, TableName extends keyof Schema = Extract<keyof Schema, string>> {
|
|
32
|
+
private schema?;
|
|
33
|
+
private rootGroup;
|
|
34
|
+
constructor(schema?: Schema | undefined);
|
|
35
|
+
/**
|
|
36
|
+
* Adds a single filter condition to the root group with an implicit AND conjunction.
|
|
37
|
+
* Performs type-safe validation if a schema is provided.
|
|
38
|
+
*/
|
|
39
|
+
add<ColumnName extends Extract<keyof Schema[TableName], string>, Op extends FilterOperator>(condition: FilterConditionInput<OperatorValueMap<InferColumnType<Schema[TableName][ColumnName]>>[Op], Schema, Schema[TableName]>): this;
|
|
40
|
+
/**
|
|
41
|
+
* Adds multiple filter conditions to the root group.
|
|
42
|
+
*/
|
|
43
|
+
addMultiple(conditions: Array<FilterConditionInput<any, Schema, Schema[TableName]>>): this;
|
|
44
|
+
/**
|
|
45
|
+
* Adds a nested group of filter conditions to the root group using the specified logical operator.
|
|
46
|
+
* @param groupConditions - Array of filter conditions or nested groups to be grouped together.
|
|
47
|
+
* @param operator - Logical operator ('AND' or 'OR') to combine the conditions in the group.
|
|
48
|
+
*/
|
|
49
|
+
addGroup(groupConditions: Array<FilterConditionInput<any, Schema, Schema[TableName]> | FilterGroup<Schema, Schema[TableName]>>, operator: 'AND' | 'OR'): this;
|
|
50
|
+
/**
|
|
51
|
+
* Returns the current filter tree representing all conditions and groups.
|
|
52
|
+
*/
|
|
53
|
+
getConditions(): FilterGroup<Schema, Schema[TableName]>;
|
|
54
|
+
/**
|
|
55
|
+
* Looks up a column's type from the schema.
|
|
56
|
+
* Defaults to 'String' if no schema is provided.
|
|
57
|
+
* @param column - The column name as a string.
|
|
58
|
+
*/
|
|
59
|
+
private getColumnType;
|
|
60
|
+
/**
|
|
61
|
+
* Validates the value of a filter condition against its expected column type.
|
|
62
|
+
*/
|
|
63
|
+
private validateValueType;
|
|
64
|
+
/**
|
|
65
|
+
* Recursively validates an array of filter conditions and nested groups.
|
|
66
|
+
*/
|
|
67
|
+
private validateGroup;
|
|
68
|
+
/**
|
|
69
|
+
* Type guard to check if an item is a FilterGroup.
|
|
70
|
+
*/
|
|
71
|
+
private isGroup;
|
|
72
|
+
private addDateCondition;
|
|
73
|
+
addDateRange<K extends keyof Schema[TableName]>(column: K extends keyof Schema[TableName] ? Schema[TableName][K] extends 'Date' | 'DateTime' ? K : never : never, range: DateRangeType): this;
|
|
74
|
+
lastNDays<K extends keyof Schema[TableName]>(column: K extends keyof Schema[TableName] ? Schema[TableName][K] extends 'Date' | 'DateTime' ? K : never : never, days: number): this;
|
|
75
|
+
addComparisonPeriod<K extends keyof Schema[TableName]>(column: K extends keyof Schema[TableName] ? Schema[TableName][K] extends 'Date' | 'DateTime' ? K : never : never, currentRange: [Date, Date]): this;
|
|
76
|
+
addYearOverYear<K extends keyof Schema[TableName]>(column: K extends keyof Schema[TableName] ? Schema[TableName][K] extends 'Date' | 'DateTime' ? K : never : never, currentRange: [Date, Date]): this;
|
|
77
|
+
/**
|
|
78
|
+
* Creates a filter for top N records by a value column
|
|
79
|
+
* @param valueColumn - The column to filter and order by
|
|
80
|
+
* @param n - Number of records to return
|
|
81
|
+
* @param orderBy - Sort direction, defaults to 'desc'
|
|
82
|
+
*/
|
|
83
|
+
topN<K extends keyof Schema[TableName]>(valueColumn: K, n: number, orderBy?: 'desc' | 'asc'): this;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=cross-filter.d.ts.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { QueryBuilder } from '../query-builder';
|
|
2
|
+
import { ColumnType } from '../../types';
|
|
3
|
+
export declare class AggregationFeature<Schema extends {
|
|
4
|
+
[tableName: string]: {
|
|
5
|
+
[columnName: string]: ColumnType;
|
|
6
|
+
};
|
|
7
|
+
}, T, HasSelect extends boolean = false, Aggregations = {}, OriginalT = T> {
|
|
8
|
+
private builder;
|
|
9
|
+
constructor(builder: QueryBuilder<Schema, T, HasSelect, Aggregations, OriginalT>);
|
|
10
|
+
private createAggregation;
|
|
11
|
+
sum<Column extends keyof OriginalT, Alias extends string = `${Column & string}_sum`>(column: Column, alias?: Alias): {
|
|
12
|
+
select: string[];
|
|
13
|
+
where?: import("../../types").WhereCondition[];
|
|
14
|
+
groupBy?: string[];
|
|
15
|
+
having?: string[];
|
|
16
|
+
limit?: number;
|
|
17
|
+
offset?: number;
|
|
18
|
+
distinct?: boolean;
|
|
19
|
+
orderBy?: {
|
|
20
|
+
column: keyof T | import("../../types").TableColumn<Schema>;
|
|
21
|
+
direction: import("../../types").OrderDirection;
|
|
22
|
+
}[] | undefined;
|
|
23
|
+
joins?: import("../../types").JoinClause[];
|
|
24
|
+
parameters?: any[];
|
|
25
|
+
ctes?: string[];
|
|
26
|
+
unionQueries?: string[];
|
|
27
|
+
settings?: string;
|
|
28
|
+
};
|
|
29
|
+
count<Column extends keyof OriginalT, Alias extends string = `${Column & string}_count`>(column: Column, alias?: Alias): {
|
|
30
|
+
select: string[];
|
|
31
|
+
where?: import("../../types").WhereCondition[];
|
|
32
|
+
groupBy?: string[];
|
|
33
|
+
having?: string[];
|
|
34
|
+
limit?: number;
|
|
35
|
+
offset?: number;
|
|
36
|
+
distinct?: boolean;
|
|
37
|
+
orderBy?: {
|
|
38
|
+
column: keyof T | import("../../types").TableColumn<Schema>;
|
|
39
|
+
direction: import("../../types").OrderDirection;
|
|
40
|
+
}[] | undefined;
|
|
41
|
+
joins?: import("../../types").JoinClause[];
|
|
42
|
+
parameters?: any[];
|
|
43
|
+
ctes?: string[];
|
|
44
|
+
unionQueries?: string[];
|
|
45
|
+
settings?: string;
|
|
46
|
+
};
|
|
47
|
+
avg<Column extends keyof OriginalT, Alias extends string = `${Column & string}_avg`>(column: Column, alias?: Alias): {
|
|
48
|
+
select: string[];
|
|
49
|
+
where?: import("../../types").WhereCondition[];
|
|
50
|
+
groupBy?: string[];
|
|
51
|
+
having?: string[];
|
|
52
|
+
limit?: number;
|
|
53
|
+
offset?: number;
|
|
54
|
+
distinct?: boolean;
|
|
55
|
+
orderBy?: {
|
|
56
|
+
column: keyof T | import("../../types").TableColumn<Schema>;
|
|
57
|
+
direction: import("../../types").OrderDirection;
|
|
58
|
+
}[] | undefined;
|
|
59
|
+
joins?: import("../../types").JoinClause[];
|
|
60
|
+
parameters?: any[];
|
|
61
|
+
ctes?: string[];
|
|
62
|
+
unionQueries?: string[];
|
|
63
|
+
settings?: string;
|
|
64
|
+
};
|
|
65
|
+
min<Column extends keyof OriginalT, Alias extends string = `${Column & string}_min`>(column: Column, alias?: Alias): {
|
|
66
|
+
select: string[];
|
|
67
|
+
where?: import("../../types").WhereCondition[];
|
|
68
|
+
groupBy?: string[];
|
|
69
|
+
having?: string[];
|
|
70
|
+
limit?: number;
|
|
71
|
+
offset?: number;
|
|
72
|
+
distinct?: boolean;
|
|
73
|
+
orderBy?: {
|
|
74
|
+
column: keyof T | import("../../types").TableColumn<Schema>;
|
|
75
|
+
direction: import("../../types").OrderDirection;
|
|
76
|
+
}[] | undefined;
|
|
77
|
+
joins?: import("../../types").JoinClause[];
|
|
78
|
+
parameters?: any[];
|
|
79
|
+
ctes?: string[];
|
|
80
|
+
unionQueries?: string[];
|
|
81
|
+
settings?: string;
|
|
82
|
+
};
|
|
83
|
+
max<Column extends keyof OriginalT, Alias extends string = `${Column & string}_max`>(column: Column, alias?: Alias): {
|
|
84
|
+
select: string[];
|
|
85
|
+
where?: import("../../types").WhereCondition[];
|
|
86
|
+
groupBy?: string[];
|
|
87
|
+
having?: string[];
|
|
88
|
+
limit?: number;
|
|
89
|
+
offset?: number;
|
|
90
|
+
distinct?: boolean;
|
|
91
|
+
orderBy?: {
|
|
92
|
+
column: keyof T | import("../../types").TableColumn<Schema>;
|
|
93
|
+
direction: import("../../types").OrderDirection;
|
|
94
|
+
}[] | undefined;
|
|
95
|
+
joins?: import("../../types").JoinClause[];
|
|
96
|
+
parameters?: any[];
|
|
97
|
+
ctes?: string[];
|
|
98
|
+
unionQueries?: string[];
|
|
99
|
+
settings?: string;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=aggregations.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { QueryBuilder } from '../query-builder';
|
|
2
|
+
import { ColumnType, TableColumn } from '../../types';
|
|
3
|
+
import { ClickHouseSettings } from '@clickhouse/client-web';
|
|
4
|
+
export declare class AnalyticsFeature<Schema extends {
|
|
5
|
+
[tableName: string]: {
|
|
6
|
+
[columnName: string]: ColumnType;
|
|
7
|
+
};
|
|
8
|
+
}, T, HasSelect extends boolean = false, Aggregations = {}, OriginalT = T> {
|
|
9
|
+
private builder;
|
|
10
|
+
constructor(builder: QueryBuilder<Schema, T, HasSelect, Aggregations, OriginalT>);
|
|
11
|
+
addCTE(alias: string, subquery: QueryBuilder<any, any> | string): {
|
|
12
|
+
ctes: string[];
|
|
13
|
+
select?: (string | keyof T)[] | undefined;
|
|
14
|
+
where?: import("../../types").WhereCondition[];
|
|
15
|
+
groupBy?: string[];
|
|
16
|
+
having?: string[];
|
|
17
|
+
limit?: number;
|
|
18
|
+
offset?: number;
|
|
19
|
+
distinct?: boolean;
|
|
20
|
+
orderBy?: {
|
|
21
|
+
column: keyof T | TableColumn<Schema>;
|
|
22
|
+
direction: import("../../types").OrderDirection;
|
|
23
|
+
}[] | undefined;
|
|
24
|
+
joins?: import("../../types").JoinClause[];
|
|
25
|
+
parameters?: any[];
|
|
26
|
+
unionQueries?: string[];
|
|
27
|
+
settings?: string;
|
|
28
|
+
};
|
|
29
|
+
addTimeInterval(column: keyof T | TableColumn<Schema>, interval: string, method: 'toStartOfInterval' | 'toStartOfMinute' | 'toStartOfHour' | 'toStartOfDay' | 'toStartOfWeek' | 'toStartOfMonth' | 'toStartOfQuarter' | 'toStartOfYear'): {
|
|
30
|
+
groupBy: string[];
|
|
31
|
+
select?: (string | keyof T)[] | undefined;
|
|
32
|
+
where?: import("../../types").WhereCondition[];
|
|
33
|
+
having?: string[];
|
|
34
|
+
limit?: number;
|
|
35
|
+
offset?: number;
|
|
36
|
+
distinct?: boolean;
|
|
37
|
+
orderBy?: {
|
|
38
|
+
column: keyof T | TableColumn<Schema>;
|
|
39
|
+
direction: import("../../types").OrderDirection;
|
|
40
|
+
}[] | undefined;
|
|
41
|
+
joins?: import("../../types").JoinClause[];
|
|
42
|
+
parameters?: any[];
|
|
43
|
+
ctes?: string[];
|
|
44
|
+
unionQueries?: string[];
|
|
45
|
+
settings?: string;
|
|
46
|
+
};
|
|
47
|
+
addSettings(opts: ClickHouseSettings): {
|
|
48
|
+
settings: string;
|
|
49
|
+
select?: (string | keyof T)[] | undefined;
|
|
50
|
+
where?: import("../../types").WhereCondition[];
|
|
51
|
+
groupBy?: string[];
|
|
52
|
+
having?: string[];
|
|
53
|
+
limit?: number;
|
|
54
|
+
offset?: number;
|
|
55
|
+
distinct?: boolean;
|
|
56
|
+
orderBy?: {
|
|
57
|
+
column: keyof T | TableColumn<Schema>;
|
|
58
|
+
direction: import("../../types").OrderDirection;
|
|
59
|
+
}[] | undefined;
|
|
60
|
+
joins?: import("../../types").JoinClause[];
|
|
61
|
+
parameters?: any[];
|
|
62
|
+
ctes?: string[];
|
|
63
|
+
unionQueries?: string[];
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=analytics.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { QueryBuilder } from '../query-builder';
|
|
2
|
+
import { CrossFilter } from '../cross-filter';
|
|
3
|
+
import { ColumnType } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* Feature for handling cross-filter operations on queries
|
|
6
|
+
*/
|
|
7
|
+
export declare class CrossFilteringFeature<Schema extends {
|
|
8
|
+
[tableName: string]: {
|
|
9
|
+
[columnName: string]: ColumnType;
|
|
10
|
+
};
|
|
11
|
+
}, T, HasSelect extends boolean = false, Aggregations = {}, OriginalT = T> {
|
|
12
|
+
private builder;
|
|
13
|
+
constructor(builder: QueryBuilder<Schema, T, HasSelect, Aggregations, OriginalT>);
|
|
14
|
+
/**
|
|
15
|
+
* Applies a set of cross filters to the query
|
|
16
|
+
* @param crossFilter - An instance of CrossFilter containing shared filter conditions
|
|
17
|
+
* @returns Updated query config
|
|
18
|
+
*/
|
|
19
|
+
applyCrossFilters(crossFilter: CrossFilter<Schema, keyof Schema>): import("../../types").QueryConfig<T, Schema>;
|
|
20
|
+
/**
|
|
21
|
+
* Apply AND conditions - each condition is applied with WHERE
|
|
22
|
+
*/
|
|
23
|
+
private applyAndConditions;
|
|
24
|
+
/**
|
|
25
|
+
* Apply direct OR conditions without adding extra conjunctions
|
|
26
|
+
* @param conditions The conditions to apply
|
|
27
|
+
* @param builder The builder to apply conditions to, defaults to this.builder
|
|
28
|
+
*/
|
|
29
|
+
private applyOrConditions;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=cross-filtering.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-filtering.d.ts","sourceRoot":"","sources":["../../../src/core/features/cross-filtering.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAe,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAwB,UAAU,EAAe,MAAM,aAAa,CAAC;AAgB5E;;GAEG;AACH,qBAAa,qBAAqB,CAChC,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;;;;OAIG;IACH,iBAAiB,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC;IAsBhE;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA4B1B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAqD1B"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
//@ts-
|
|
2
|
+
/**
|
|
3
|
+
* Type guard to check if an object is a FilterConditionInput
|
|
4
|
+
*/
|
|
5
|
+
function isFilterCondition(obj) {
|
|
6
|
+
return obj && 'column' in obj && 'operator' in obj && 'value' in obj;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Type guard to check if an object is a FilterGroup
|
|
10
|
+
*/
|
|
11
|
+
function isFilterGroup(obj) {
|
|
12
|
+
return obj && 'conditions' in obj && 'operator' in obj;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Feature for handling cross-filter operations on queries
|
|
16
|
+
*/
|
|
17
|
+
export class CrossFilteringFeature {
|
|
18
|
+
constructor(builder) {
|
|
19
|
+
this.builder = builder;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Applies a set of cross filters to the query
|
|
23
|
+
* @param crossFilter - An instance of CrossFilter containing shared filter conditions
|
|
24
|
+
* @returns Updated query config
|
|
25
|
+
*/
|
|
26
|
+
applyCrossFilters(crossFilter) {
|
|
27
|
+
const filterGroup = crossFilter.getConditions();
|
|
28
|
+
if (filterGroup.conditions.length === 0) {
|
|
29
|
+
return this.builder.getConfig();
|
|
30
|
+
}
|
|
31
|
+
// Apply conditions based on filter group operator
|
|
32
|
+
if (filterGroup.operator === 'AND') {
|
|
33
|
+
// For AND groups, apply each condition directly
|
|
34
|
+
this.applyAndConditions(filterGroup.conditions);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// For OR groups, special handling to ensure proper parentheses
|
|
38
|
+
// We use whereGroup instead of orWhereGroup here since this is a top-level group
|
|
39
|
+
this.builder.whereGroup(builder => {
|
|
40
|
+
this.applyOrConditions(filterGroup.conditions, builder);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return this.builder.getConfig();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Apply AND conditions - each condition is applied with WHERE
|
|
47
|
+
*/
|
|
48
|
+
applyAndConditions(conditions) {
|
|
49
|
+
conditions.forEach(condition => {
|
|
50
|
+
if (isFilterCondition(condition)) {
|
|
51
|
+
// Simple condition - apply with WHERE
|
|
52
|
+
this.builder.where(condition.column, condition.operator, condition.value);
|
|
53
|
+
}
|
|
54
|
+
else if (isFilterGroup(condition)) {
|
|
55
|
+
// Nested group
|
|
56
|
+
if (condition.operator === 'AND') {
|
|
57
|
+
// AND subgroup - apply all conditions
|
|
58
|
+
this.builder.whereGroup(builder => {
|
|
59
|
+
const feature = new CrossFilteringFeature(builder);
|
|
60
|
+
feature.applyAndConditions(condition.conditions);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// OR subgroup within AND - needs special parentheses handling
|
|
65
|
+
this.builder.whereGroup(builder => {
|
|
66
|
+
const feature = new CrossFilteringFeature(builder);
|
|
67
|
+
feature.applyOrConditions(condition.conditions, builder);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Apply direct OR conditions without adding extra conjunctions
|
|
75
|
+
* @param conditions The conditions to apply
|
|
76
|
+
* @param builder The builder to apply conditions to, defaults to this.builder
|
|
77
|
+
*/
|
|
78
|
+
applyOrConditions(conditions, builder = this.builder) {
|
|
79
|
+
if (conditions.length === 0)
|
|
80
|
+
return;
|
|
81
|
+
// Handle first condition
|
|
82
|
+
const firstCondition = conditions[0];
|
|
83
|
+
if (isFilterCondition(firstCondition)) {
|
|
84
|
+
builder.where(firstCondition.column, firstCondition.operator, firstCondition.value);
|
|
85
|
+
}
|
|
86
|
+
else if (isFilterGroup(firstCondition)) {
|
|
87
|
+
// Handle nested group
|
|
88
|
+
if (firstCondition.operator === 'AND') {
|
|
89
|
+
builder.whereGroup(innerBuilder => {
|
|
90
|
+
const feature = new CrossFilteringFeature(innerBuilder);
|
|
91
|
+
feature.applyAndConditions(firstCondition.conditions);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
builder.whereGroup(innerBuilder => {
|
|
96
|
+
const feature = new CrossFilteringFeature(innerBuilder);
|
|
97
|
+
feature.applyOrConditions(firstCondition.conditions, innerBuilder);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Handle remaining conditions
|
|
102
|
+
for (let i = 1; i < conditions.length; i++) {
|
|
103
|
+
const condition = conditions[i];
|
|
104
|
+
if (isFilterCondition(condition)) {
|
|
105
|
+
builder.orWhere(condition.column, condition.operator, condition.value);
|
|
106
|
+
}
|
|
107
|
+
else if (isFilterGroup(condition)) {
|
|
108
|
+
if (condition.operator === 'AND') {
|
|
109
|
+
builder.orWhereGroup(innerBuilder => {
|
|
110
|
+
const feature = new CrossFilteringFeature(innerBuilder);
|
|
111
|
+
feature.applyAndConditions(condition.conditions);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
builder.orWhereGroup(innerBuilder => {
|
|
116
|
+
const feature = new CrossFilteringFeature(innerBuilder);
|
|
117
|
+
feature.applyOrConditions(condition.conditions, innerBuilder);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { QueryBuilder } from '../query-builder';
|
|
2
|
+
import { ColumnType } from '../../types';
|
|
3
|
+
export declare class ExecutorFeature<Schema extends {
|
|
4
|
+
[tableName: string]: {
|
|
5
|
+
[columnName: string]: ColumnType;
|
|
6
|
+
};
|
|
7
|
+
}, T, HasSelect extends boolean = false, Aggregations = {}, OriginalT = T> {
|
|
8
|
+
private builder;
|
|
9
|
+
constructor(builder: QueryBuilder<Schema, T, HasSelect, Aggregations, OriginalT>);
|
|
10
|
+
toSQLWithParams(): {
|
|
11
|
+
sql: string;
|
|
12
|
+
parameters: any[];
|
|
13
|
+
};
|
|
14
|
+
toSQL(): string;
|
|
15
|
+
execute(): Promise<T[]>;
|
|
16
|
+
stream(): Promise<ReadableStream<T[]>>;
|
|
17
|
+
private toSQLWithoutParameters;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { QueryBuilder } from '../query-builder';
|
|
2
|
+
import { ColumnType, FilterOperator, TableColumn } from '../../types';
|
|
3
|
+
export declare class FilteringFeature<Schema extends {
|
|
4
|
+
[tableName: string]: {
|
|
5
|
+
[columnName: string]: ColumnType;
|
|
6
|
+
};
|
|
7
|
+
}, T, HasSelect extends boolean = false, Aggregations = {}, OriginalT = T> {
|
|
8
|
+
private builder;
|
|
9
|
+
constructor(builder: QueryBuilder<Schema, T, HasSelect, Aggregations, OriginalT>);
|
|
10
|
+
addCondition<K extends keyof OriginalT | TableColumn<Schema>>(conjunction: 'AND' | 'OR', column: K, operator: FilterOperator, value: any): {
|
|
11
|
+
where: import("../../types").WhereCondition[];
|
|
12
|
+
parameters: any[];
|
|
13
|
+
select?: (string | keyof T)[] | undefined;
|
|
14
|
+
groupBy?: string[];
|
|
15
|
+
having?: string[];
|
|
16
|
+
limit?: number;
|
|
17
|
+
offset?: number;
|
|
18
|
+
distinct?: boolean;
|
|
19
|
+
orderBy?: {
|
|
20
|
+
column: TableColumn<Schema> | keyof T;
|
|
21
|
+
direction: import("../../types").OrderDirection;
|
|
22
|
+
}[] | undefined;
|
|
23
|
+
joins?: import("../../types").JoinClause[];
|
|
24
|
+
ctes?: string[];
|
|
25
|
+
unionQueries?: string[];
|
|
26
|
+
settings?: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Adds a group-start marker to start a parenthesized group of conditions with AND conjunction
|
|
30
|
+
* @returns The updated query config
|
|
31
|
+
*/
|
|
32
|
+
startWhereGroup(): {
|
|
33
|
+
where: import("../../types").WhereCondition[];
|
|
34
|
+
select?: (string | keyof T)[] | undefined;
|
|
35
|
+
groupBy?: string[];
|
|
36
|
+
having?: string[];
|
|
37
|
+
limit?: number;
|
|
38
|
+
offset?: number;
|
|
39
|
+
distinct?: boolean;
|
|
40
|
+
orderBy?: {
|
|
41
|
+
column: TableColumn<Schema> | keyof T;
|
|
42
|
+
direction: import("../../types").OrderDirection;
|
|
43
|
+
}[] | undefined;
|
|
44
|
+
joins?: import("../../types").JoinClause[];
|
|
45
|
+
parameters?: any[];
|
|
46
|
+
ctes?: string[];
|
|
47
|
+
unionQueries?: string[];
|
|
48
|
+
settings?: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Adds a group-start marker to start a parenthesized group of conditions with OR conjunction
|
|
52
|
+
* @returns The updated query config
|
|
53
|
+
*/
|
|
54
|
+
startOrWhereGroup(): {
|
|
55
|
+
where: import("../../types").WhereCondition[];
|
|
56
|
+
select?: (string | keyof T)[] | undefined;
|
|
57
|
+
groupBy?: string[];
|
|
58
|
+
having?: string[];
|
|
59
|
+
limit?: number;
|
|
60
|
+
offset?: number;
|
|
61
|
+
distinct?: boolean;
|
|
62
|
+
orderBy?: {
|
|
63
|
+
column: TableColumn<Schema> | keyof T;
|
|
64
|
+
direction: import("../../types").OrderDirection;
|
|
65
|
+
}[] | undefined;
|
|
66
|
+
joins?: import("../../types").JoinClause[];
|
|
67
|
+
parameters?: any[];
|
|
68
|
+
ctes?: string[];
|
|
69
|
+
unionQueries?: string[];
|
|
70
|
+
settings?: string;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Adds a group-end marker to end a parenthesized group of conditions
|
|
74
|
+
* @returns The updated query config
|
|
75
|
+
*/
|
|
76
|
+
endWhereGroup(): {
|
|
77
|
+
where: import("../../types").WhereCondition[];
|
|
78
|
+
select?: (string | keyof T)[] | undefined;
|
|
79
|
+
groupBy?: string[];
|
|
80
|
+
having?: string[];
|
|
81
|
+
limit?: number;
|
|
82
|
+
offset?: number;
|
|
83
|
+
distinct?: boolean;
|
|
84
|
+
orderBy?: {
|
|
85
|
+
column: TableColumn<Schema> | keyof T;
|
|
86
|
+
direction: import("../../types").OrderDirection;
|
|
87
|
+
}[] | undefined;
|
|
88
|
+
joins?: import("../../types").JoinClause[];
|
|
89
|
+
parameters?: any[];
|
|
90
|
+
ctes?: string[];
|
|
91
|
+
unionQueries?: string[];
|
|
92
|
+
settings?: string;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=filtering.d.ts.map
|
|
@@ -1 +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;;;;;;;;;;;;;;;;;;
|
|
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;;;;;;;;;;;;;;;;;;IA+BZ;;;OAGG;IACH,eAAe;;;;;;;;;;;;;;;;;;IAkBf;;;OAGG;IACH,iBAAiB;;;;;;;;;;;;;;;;;;IAkBjB;;;OAGG;IACH,aAAa;;;;;;;;;;;;;;;;;;CAiBd"}
|
|
@@ -10,7 +10,8 @@ export class FilteringFeature {
|
|
|
10
10
|
column: String(column),
|
|
11
11
|
operator,
|
|
12
12
|
value,
|
|
13
|
-
conjunction
|
|
13
|
+
conjunction,
|
|
14
|
+
type: 'condition'
|
|
14
15
|
});
|
|
15
16
|
if (operator === 'in' || operator === 'notIn') {
|
|
16
17
|
parameters.push(...value);
|
|
@@ -27,4 +28,61 @@ export class FilteringFeature {
|
|
|
27
28
|
parameters
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Adds a group-start marker to start a parenthesized group of conditions with AND conjunction
|
|
33
|
+
* @returns The updated query config
|
|
34
|
+
*/
|
|
35
|
+
startWhereGroup() {
|
|
36
|
+
const config = this.builder.getConfig();
|
|
37
|
+
const where = config.where || [];
|
|
38
|
+
where.push({
|
|
39
|
+
column: '', // Not used for group markers
|
|
40
|
+
operator: 'eq', // Not used for group markers
|
|
41
|
+
value: null, // Not used for group markers
|
|
42
|
+
conjunction: 'AND',
|
|
43
|
+
type: 'group-start'
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
...config,
|
|
47
|
+
where
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Adds a group-start marker to start a parenthesized group of conditions with OR conjunction
|
|
52
|
+
* @returns The updated query config
|
|
53
|
+
*/
|
|
54
|
+
startOrWhereGroup() {
|
|
55
|
+
const config = this.builder.getConfig();
|
|
56
|
+
const where = config.where || [];
|
|
57
|
+
where.push({
|
|
58
|
+
column: '', // Not used for group markers
|
|
59
|
+
operator: 'eq', // Not used for group markers
|
|
60
|
+
value: null, // Not used for group markers
|
|
61
|
+
conjunction: 'OR',
|
|
62
|
+
type: 'group-start'
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
...config,
|
|
66
|
+
where
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Adds a group-end marker to end a parenthesized group of conditions
|
|
71
|
+
* @returns The updated query config
|
|
72
|
+
*/
|
|
73
|
+
endWhereGroup() {
|
|
74
|
+
const config = this.builder.getConfig();
|
|
75
|
+
const where = config.where || [];
|
|
76
|
+
where.push({
|
|
77
|
+
column: '', // Not used for group markers
|
|
78
|
+
operator: 'eq', // Not used for group markers
|
|
79
|
+
value: null, // Not used for group markers
|
|
80
|
+
conjunction: 'AND', // Not relevant for end markers
|
|
81
|
+
type: 'group-end'
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
...config,
|
|
85
|
+
where
|
|
86
|
+
};
|
|
87
|
+
}
|
|
30
88
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { QueryBuilder } from '../query-builder';
|
|
2
|
+
import { ColumnType, JoinType } from '../../types';
|
|
3
|
+
export declare class JoinFeature<Schema extends {
|
|
4
|
+
[tableName: string]: {
|
|
5
|
+
[columnName: string]: ColumnType;
|
|
6
|
+
};
|
|
7
|
+
}, T, HasSelect extends boolean = false, Aggregations = {}, OriginalT = T> {
|
|
8
|
+
private builder;
|
|
9
|
+
constructor(builder: QueryBuilder<Schema, T, HasSelect, Aggregations, OriginalT>);
|
|
10
|
+
addJoin<TableName extends keyof Schema>(type: JoinType, table: TableName, leftColumn: keyof OriginalT, rightColumn: `${TableName & string}.${keyof Schema[TableName] & string}`, alias?: string): {
|
|
11
|
+
joins: import("../../types").JoinClause[];
|
|
12
|
+
select?: (string | keyof T)[] | undefined;
|
|
13
|
+
where?: import("../../types").WhereCondition[];
|
|
14
|
+
groupBy?: string[];
|
|
15
|
+
having?: string[];
|
|
16
|
+
limit?: number;
|
|
17
|
+
offset?: number;
|
|
18
|
+
distinct?: boolean;
|
|
19
|
+
orderBy?: {
|
|
20
|
+
column: keyof T | import("../../types").TableColumn<Schema>;
|
|
21
|
+
direction: import("../../types").OrderDirection;
|
|
22
|
+
}[] | undefined;
|
|
23
|
+
parameters?: any[];
|
|
24
|
+
ctes?: string[];
|
|
25
|
+
unionQueries?: string[];
|
|
26
|
+
settings?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=joins.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { QueryBuilder } from '../query-builder';
|
|
2
|
+
import { ColumnType, PaginationOptions, PaginatedResult } from '../../types';
|
|
3
|
+
export declare class PaginationFeature<Schema extends {
|
|
4
|
+
[tableName: string]: {
|
|
5
|
+
[columnName: string]: ColumnType;
|
|
6
|
+
};
|
|
7
|
+
}, T, HasSelect extends boolean = false, Aggregations = {}, OriginalT = T> {
|
|
8
|
+
private builder;
|
|
9
|
+
private static cursorStacks;
|
|
10
|
+
private stackKey;
|
|
11
|
+
constructor(builder: QueryBuilder<Schema, T, HasSelect, Aggregations, OriginalT>);
|
|
12
|
+
private get cursorStack();
|
|
13
|
+
private set cursorStack(value);
|
|
14
|
+
private get currentPosition();
|
|
15
|
+
private set currentPosition(value);
|
|
16
|
+
private encodeCursor;
|
|
17
|
+
private decodeCursor;
|
|
18
|
+
paginate(options: PaginationOptions<T>): Promise<PaginatedResult<T>>;
|
|
19
|
+
private generateCursor;
|
|
20
|
+
firstPage(pageSize: number): Promise<PaginatedResult<T>>;
|
|
21
|
+
iteratePages(pageSize: number): AsyncGenerator<PaginatedResult<T>>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=pagination.d.ts.map
|