@visactor/vquery 0.4.16 → 0.4.19

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.
@@ -114,6 +114,36 @@ const applyGroupBy = (qb, fields)=>{
114
114
  }
115
115
  return qb;
116
116
  };
117
+ const AGGREGATE_FUNCTIONS = [
118
+ 'sum',
119
+ 'avg',
120
+ 'count',
121
+ 'count_distinct',
122
+ 'min',
123
+ 'max',
124
+ 'variance',
125
+ 'variance_pop',
126
+ 'stddev',
127
+ 'median',
128
+ 'quantile'
129
+ ];
130
+ const isAggregateFunction = (func)=>AGGREGATE_FUNCTIONS.includes(func);
131
+ const toAggregateExpression = (func, field, aggr)=>{
132
+ switch(func){
133
+ case 'count':
134
+ return external_kysely_sql`count(${external_kysely_sql.ref(field)})`;
135
+ case 'count_distinct':
136
+ return external_kysely_sql`count(distinct ${external_kysely_sql.ref(field)})`;
137
+ case 'variance':
138
+ return external_kysely_sql`var_samp(${external_kysely_sql.ref(field)})`;
139
+ case 'variance_pop':
140
+ return external_kysely_sql`var_pop(${external_kysely_sql.ref(field)})`;
141
+ case 'quantile':
142
+ return external_kysely_sql`quantile(${external_kysely_sql.ref(field)}, ${aggr?.quantile ?? 0.5})`;
143
+ default:
144
+ return external_kysely_sql`${external_kysely_sql.raw(func)}(${external_kysely_sql.ref(field)})`;
145
+ }
146
+ };
117
147
  const applyHaving = (qb, having)=>{
118
148
  if (!having) return qb;
119
149
  const toRaw = (h)=>{
@@ -125,48 +155,40 @@ const applyHaving = (qb, having)=>{
125
155
  const leaf = h;
126
156
  const field = leaf.field;
127
157
  const value = leaf.value;
128
- const op = toSqlOperator(leaf.op);
129
- if ([
130
- 'sum',
131
- 'avg',
132
- 'count',
133
- 'min',
134
- 'max'
135
- ].includes(op)) {
136
- const aggrExpr = external_kysely_sql`${external_kysely_sql.raw(op.toLowerCase())}(${external_kysely_sql.ref(field)})`;
137
- return external_kysely_sql`${aggrExpr} = ${external_kysely_sql.val(value)}`;
138
- }
139
- switch(leaf.op){
158
+ if (!leaf.aggr?.func || !isAggregateFunction(leaf.aggr.func)) throw new Error(`Invalid having clause for field "${String(field)}": aggr.func is required`);
159
+ const compareOp = toSqlOperator(leaf.op.trim().toLowerCase());
160
+ const leftExpr = toAggregateExpression(leaf.aggr.func, field, leaf.aggr);
161
+ switch(compareOp){
140
162
  case 'is null':
141
- return external_kysely_sql`${external_kysely_sql.ref(field)} is null`;
163
+ return external_kysely_sql`${leftExpr} is null`;
142
164
  case 'is not null':
143
- return external_kysely_sql`${external_kysely_sql.ref(field)} is not null`;
165
+ return external_kysely_sql`${leftExpr} is not null`;
144
166
  case 'in':
145
167
  {
146
168
  const items = Array.isArray(value) ? value : [
147
169
  value
148
170
  ];
149
- return external_kysely_sql`${external_kysely_sql.ref(field)} in (${external_kysely_sql.join(items.map((v)=>external_kysely_sql.val(v)))})`;
171
+ return external_kysely_sql`${leftExpr} in (${external_kysely_sql.join(items.map((v)=>external_kysely_sql.val(v)))})`;
150
172
  }
151
173
  case 'not in':
152
174
  {
153
175
  const items = Array.isArray(value) ? value : [
154
176
  value
155
177
  ];
156
- return external_kysely_sql`not ${external_kysely_sql.ref(field)} in (${external_kysely_sql.join(items.map((v)=>external_kysely_sql.val(v)))})`;
178
+ return external_kysely_sql`not ${leftExpr} in (${external_kysely_sql.join(items.map((v)=>external_kysely_sql.val(v)))})`;
157
179
  }
158
180
  case 'between':
159
181
  {
160
182
  const [a, b] = value;
161
- return external_kysely_sql`${external_kysely_sql.ref(field)} between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
183
+ return external_kysely_sql`${leftExpr} between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
162
184
  }
163
185
  case 'not between':
164
186
  {
165
187
  const [a, b] = value;
166
- return external_kysely_sql`${external_kysely_sql.ref(field)} not between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
188
+ return external_kysely_sql`${leftExpr} not between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
167
189
  }
168
190
  default:
169
- return external_kysely_sql`${external_kysely_sql.ref(field)} ${external_kysely_sql.raw(op)} ${external_kysely_sql.val(value)}`;
191
+ return external_kysely_sql`${leftExpr} ${external_kysely_sql.raw(compareOp)} ${external_kysely_sql.val(value)}`;
170
192
  }
171
193
  };
172
194
  return qb.having(toRaw(having));
@@ -204,12 +226,12 @@ const applySelect = (qb, select)=>{
204
226
  'min',
205
227
  'max',
206
228
  'variance',
207
- 'variancePop',
229
+ 'variance_pop',
208
230
  'stddev',
209
231
  'median'
210
232
  ].includes(func)) {
211
233
  if ('variance' === func) return external_kysely_sql`var_samp(${expression})`.as(alias);
212
- if ('variancePop' === func) return external_kysely_sql`var_pop(${expression})`.as(alias);
234
+ if ('variance_pop' === func) return external_kysely_sql`var_pop(${expression})`.as(alias);
213
235
  return external_kysely_sql`${external_kysely_sql.raw(func)}(${expression})`.as(alias);
214
236
  }
215
237
  if ('count' === func) return external_kysely_sql`CAST(count(${expression}) AS INTEGER)`.as(alias);
@@ -1,3 +1,3 @@
1
1
  import type { SelectQueryBuilder } from 'kysely';
2
- import { Having, HavingClause } from '../../types';
2
+ import type { Having, HavingClause } from '../../types';
3
3
  export declare const applyHaving: <DB, TB extends keyof DB & string, O, T>(qb: SelectQueryBuilder<DB, TB, O>, having?: Having<T> | HavingClause<T>) => SelectQueryBuilder<DB, TB, O>;
@@ -2,6 +2,7 @@
2
2
  * Having 子句类型定义
3
3
  * 用于聚合后的数据筛选
4
4
  */
5
+ import type { BaseAggregateFunction } from './Select';
5
6
  export type Having<T> = HavingGroup<T>;
6
7
  export type HavingGroup<T> = {
7
8
  op: 'and' | 'or';
@@ -10,13 +11,14 @@ export type HavingGroup<T> = {
10
11
  export type HavingClause<T> = HavingLeaf<T> | HavingGroup<T>;
11
12
  /**
12
13
  * Having 叶子节点
13
- * 支持聚合函数操作符
14
+ * 通过 aggr 指定聚合方式,通过 op 指定比较操作符
14
15
  */
15
16
  export type HavingLeaf<T> = {
16
17
  [K in keyof T]: {
17
- [O in HavingOperator]: {
18
+ [O in HavingComparisonOperator]: {
18
19
  field: K;
19
20
  op: O;
21
+ aggr: HavingAggregation;
20
22
  } & (O extends 'is null' | 'is not null' ? {
21
23
  value?: never;
22
24
  } : O extends 'in' | 'not in' ? {
@@ -26,10 +28,21 @@ export type HavingLeaf<T> = {
26
28
  } : {
27
29
  value: T[K];
28
30
  });
29
- }[HavingOperator];
31
+ }[HavingComparisonOperator];
30
32
  }[keyof T];
31
33
  /**
32
- * Having 操作符
33
- * 聚合函数操作符
34
+ * Having 聚合函数
34
35
  */
35
- export type HavingOperator = 'sum' | 'avg' | 'count' | 'min' | 'max' | '=' | '!=' | '>' | '>=' | '<' | '<=' | 'between' | 'not between' | 'in' | 'not in' | 'is null' | 'is not null';
36
+ export type HavingAggregateFunction = BaseAggregateFunction;
37
+ export type HavingAggregation = {
38
+ func: HavingAggregateFunction;
39
+ quantile?: number;
40
+ };
41
+ /**
42
+ * Having 比较操作符
43
+ */
44
+ export type HavingComparisonOperator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'between' | 'not between' | 'in' | 'not in' | 'is null' | 'is not null';
45
+ /**
46
+ * Having 操作符(仅比较操作符)
47
+ */
48
+ export type HavingOperator = HavingComparisonOperator;
@@ -1,4 +1,4 @@
1
- export type BaseAggregateFunction = 'count' | 'count_distinct' | 'sum' | 'avg' | 'min' | 'max' | 'variance' | 'variancePop' | 'stddev' | 'median' | 'quantile';
1
+ export type BaseAggregateFunction = 'count' | 'count_distinct' | 'sum' | 'avg' | 'min' | 'max' | 'variance' | 'variance_pop' | 'stddev' | 'median' | 'quantile';
2
2
  export type DateAggregateFunction = 'to_year' | 'to_quarter' | 'to_month' | 'to_week' | 'to_day' | 'to_hour' | 'to_minute' | 'to_second';
3
3
  export type AggregateFunction = BaseAggregateFunction | DateAggregateFunction;
4
4
  export type SelectItem<T> = {
@@ -3,4 +3,4 @@ export type { GroupBy } from './GroupBy';
3
3
  export type { OrderBy } from './OrderBy';
4
4
  export type { Select } from './Select';
5
5
  export type { Where, WhereClause, WhereLeaf, WhereGroup } from './Where';
6
- export type { Having, HavingClause, HavingLeaf, HavingGroup, HavingOperator } from './Having';
6
+ export type { Having, HavingClause, HavingLeaf, HavingGroup, HavingOperator, HavingAggregation, HavingAggregateFunction, HavingComparisonOperator, } from './Having';
@@ -151,6 +151,36 @@ const applyGroupBy = (qb, fields)=>{
151
151
  }
152
152
  return qb;
153
153
  };
154
+ const AGGREGATE_FUNCTIONS = [
155
+ 'sum',
156
+ 'avg',
157
+ 'count',
158
+ 'count_distinct',
159
+ 'min',
160
+ 'max',
161
+ 'variance',
162
+ 'variance_pop',
163
+ 'stddev',
164
+ 'median',
165
+ 'quantile'
166
+ ];
167
+ const isAggregateFunction = (func)=>AGGREGATE_FUNCTIONS.includes(func);
168
+ const toAggregateExpression = (func, field, aggr)=>{
169
+ switch(func){
170
+ case 'count':
171
+ return (0, external_kysely_namespaceObject.sql)`count(${external_kysely_namespaceObject.sql.ref(field)})`;
172
+ case 'count_distinct':
173
+ return (0, external_kysely_namespaceObject.sql)`count(distinct ${external_kysely_namespaceObject.sql.ref(field)})`;
174
+ case 'variance':
175
+ return (0, external_kysely_namespaceObject.sql)`var_samp(${external_kysely_namespaceObject.sql.ref(field)})`;
176
+ case 'variance_pop':
177
+ return (0, external_kysely_namespaceObject.sql)`var_pop(${external_kysely_namespaceObject.sql.ref(field)})`;
178
+ case 'quantile':
179
+ return (0, external_kysely_namespaceObject.sql)`quantile(${external_kysely_namespaceObject.sql.ref(field)}, ${aggr?.quantile ?? 0.5})`;
180
+ default:
181
+ return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.raw(func)}(${external_kysely_namespaceObject.sql.ref(field)})`;
182
+ }
183
+ };
154
184
  const applyHaving = (qb, having)=>{
155
185
  if (!having) return qb;
156
186
  const toRaw = (h)=>{
@@ -162,48 +192,40 @@ const applyHaving = (qb, having)=>{
162
192
  const leaf = h;
163
193
  const field = leaf.field;
164
194
  const value = leaf.value;
165
- const op = toSqlOperator(leaf.op);
166
- if ([
167
- 'sum',
168
- 'avg',
169
- 'count',
170
- 'min',
171
- 'max'
172
- ].includes(op)) {
173
- const aggrExpr = (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.raw(op.toLowerCase())}(${external_kysely_namespaceObject.sql.ref(field)})`;
174
- return (0, external_kysely_namespaceObject.sql)`${aggrExpr} = ${external_kysely_namespaceObject.sql.val(value)}`;
175
- }
176
- switch(leaf.op){
195
+ if (!leaf.aggr?.func || !isAggregateFunction(leaf.aggr.func)) throw new Error(`Invalid having clause for field "${String(field)}": aggr.func is required`);
196
+ const compareOp = toSqlOperator(leaf.op.trim().toLowerCase());
197
+ const leftExpr = toAggregateExpression(leaf.aggr.func, field, leaf.aggr);
198
+ switch(compareOp){
177
199
  case 'is null':
178
- return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} is null`;
200
+ return (0, external_kysely_namespaceObject.sql)`${leftExpr} is null`;
179
201
  case 'is not null':
180
- return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} is not null`;
202
+ return (0, external_kysely_namespaceObject.sql)`${leftExpr} is not null`;
181
203
  case 'in':
182
204
  {
183
205
  const items = Array.isArray(value) ? value : [
184
206
  value
185
207
  ];
186
- return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} in (${external_kysely_namespaceObject.sql.join(items.map((v)=>external_kysely_namespaceObject.sql.val(v)))})`;
208
+ return (0, external_kysely_namespaceObject.sql)`${leftExpr} in (${external_kysely_namespaceObject.sql.join(items.map((v)=>external_kysely_namespaceObject.sql.val(v)))})`;
187
209
  }
188
210
  case 'not in':
189
211
  {
190
212
  const items = Array.isArray(value) ? value : [
191
213
  value
192
214
  ];
193
- return (0, external_kysely_namespaceObject.sql)`not ${external_kysely_namespaceObject.sql.ref(field)} in (${external_kysely_namespaceObject.sql.join(items.map((v)=>external_kysely_namespaceObject.sql.val(v)))})`;
215
+ return (0, external_kysely_namespaceObject.sql)`not ${leftExpr} in (${external_kysely_namespaceObject.sql.join(items.map((v)=>external_kysely_namespaceObject.sql.val(v)))})`;
194
216
  }
195
217
  case 'between':
196
218
  {
197
219
  const [a, b] = value;
198
- return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} between ${external_kysely_namespaceObject.sql.val(a)} and ${external_kysely_namespaceObject.sql.val(b)}`;
220
+ return (0, external_kysely_namespaceObject.sql)`${leftExpr} between ${external_kysely_namespaceObject.sql.val(a)} and ${external_kysely_namespaceObject.sql.val(b)}`;
199
221
  }
200
222
  case 'not between':
201
223
  {
202
224
  const [a, b] = value;
203
- return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} not between ${external_kysely_namespaceObject.sql.val(a)} and ${external_kysely_namespaceObject.sql.val(b)}`;
225
+ return (0, external_kysely_namespaceObject.sql)`${leftExpr} not between ${external_kysely_namespaceObject.sql.val(a)} and ${external_kysely_namespaceObject.sql.val(b)}`;
204
226
  }
205
227
  default:
206
- return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} ${external_kysely_namespaceObject.sql.raw(op)} ${external_kysely_namespaceObject.sql.val(value)}`;
228
+ return (0, external_kysely_namespaceObject.sql)`${leftExpr} ${external_kysely_namespaceObject.sql.raw(compareOp)} ${external_kysely_namespaceObject.sql.val(value)}`;
207
229
  }
208
230
  };
209
231
  return qb.having(toRaw(having));
@@ -242,12 +264,12 @@ const applySelect = (qb, select)=>{
242
264
  'min',
243
265
  'max',
244
266
  'variance',
245
- 'variancePop',
267
+ 'variance_pop',
246
268
  'stddev',
247
269
  'median'
248
270
  ].includes(func)) {
249
271
  if ('variance' === func) return (0, external_kysely_namespaceObject.sql)`var_samp(${expression})`.as(alias);
250
- if ('variancePop' === func) return (0, external_kysely_namespaceObject.sql)`var_pop(${expression})`.as(alias);
272
+ if ('variance_pop' === func) return (0, external_kysely_namespaceObject.sql)`var_pop(${expression})`.as(alias);
251
273
  return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.raw(func)}(${expression})`.as(alias);
252
274
  }
253
275
  if ('count' === func) return (0, external_kysely_namespaceObject.sql)`CAST(count(${expression}) AS INTEGER)`.as(alias);
@@ -1,3 +1,3 @@
1
1
  import type { SelectQueryBuilder } from 'kysely';
2
- import { Having, HavingClause } from '../../types';
2
+ import type { Having, HavingClause } from '../../types';
3
3
  export declare const applyHaving: <DB, TB extends keyof DB & string, O, T>(qb: SelectQueryBuilder<DB, TB, O>, having?: Having<T> | HavingClause<T>) => SelectQueryBuilder<DB, TB, O>;
@@ -2,6 +2,7 @@
2
2
  * Having 子句类型定义
3
3
  * 用于聚合后的数据筛选
4
4
  */
5
+ import type { BaseAggregateFunction } from './Select';
5
6
  export type Having<T> = HavingGroup<T>;
6
7
  export type HavingGroup<T> = {
7
8
  op: 'and' | 'or';
@@ -10,13 +11,14 @@ export type HavingGroup<T> = {
10
11
  export type HavingClause<T> = HavingLeaf<T> | HavingGroup<T>;
11
12
  /**
12
13
  * Having 叶子节点
13
- * 支持聚合函数操作符
14
+ * 通过 aggr 指定聚合方式,通过 op 指定比较操作符
14
15
  */
15
16
  export type HavingLeaf<T> = {
16
17
  [K in keyof T]: {
17
- [O in HavingOperator]: {
18
+ [O in HavingComparisonOperator]: {
18
19
  field: K;
19
20
  op: O;
21
+ aggr: HavingAggregation;
20
22
  } & (O extends 'is null' | 'is not null' ? {
21
23
  value?: never;
22
24
  } : O extends 'in' | 'not in' ? {
@@ -26,10 +28,21 @@ export type HavingLeaf<T> = {
26
28
  } : {
27
29
  value: T[K];
28
30
  });
29
- }[HavingOperator];
31
+ }[HavingComparisonOperator];
30
32
  }[keyof T];
31
33
  /**
32
- * Having 操作符
33
- * 聚合函数操作符
34
+ * Having 聚合函数
34
35
  */
35
- export type HavingOperator = 'sum' | 'avg' | 'count' | 'min' | 'max' | '=' | '!=' | '>' | '>=' | '<' | '<=' | 'between' | 'not between' | 'in' | 'not in' | 'is null' | 'is not null';
36
+ export type HavingAggregateFunction = BaseAggregateFunction;
37
+ export type HavingAggregation = {
38
+ func: HavingAggregateFunction;
39
+ quantile?: number;
40
+ };
41
+ /**
42
+ * Having 比较操作符
43
+ */
44
+ export type HavingComparisonOperator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'between' | 'not between' | 'in' | 'not in' | 'is null' | 'is not null';
45
+ /**
46
+ * Having 操作符(仅比较操作符)
47
+ */
48
+ export type HavingOperator = HavingComparisonOperator;
@@ -1,4 +1,4 @@
1
- export type BaseAggregateFunction = 'count' | 'count_distinct' | 'sum' | 'avg' | 'min' | 'max' | 'variance' | 'variancePop' | 'stddev' | 'median' | 'quantile';
1
+ export type BaseAggregateFunction = 'count' | 'count_distinct' | 'sum' | 'avg' | 'min' | 'max' | 'variance' | 'variance_pop' | 'stddev' | 'median' | 'quantile';
2
2
  export type DateAggregateFunction = 'to_year' | 'to_quarter' | 'to_month' | 'to_week' | 'to_day' | 'to_hour' | 'to_minute' | 'to_second';
3
3
  export type AggregateFunction = BaseAggregateFunction | DateAggregateFunction;
4
4
  export type SelectItem<T> = {
@@ -3,4 +3,4 @@ export type { GroupBy } from './GroupBy';
3
3
  export type { OrderBy } from './OrderBy';
4
4
  export type { Select } from './Select';
5
5
  export type { Where, WhereClause, WhereLeaf, WhereGroup } from './Where';
6
- export type { Having, HavingClause, HavingLeaf, HavingGroup, HavingOperator } from './Having';
6
+ export type { Having, HavingClause, HavingLeaf, HavingGroup, HavingOperator, HavingAggregation, HavingAggregateFunction, HavingComparisonOperator, } from './Having';
@@ -115,6 +115,36 @@ const applyGroupBy = (qb, fields)=>{
115
115
  }
116
116
  return qb;
117
117
  };
118
+ const AGGREGATE_FUNCTIONS = [
119
+ 'sum',
120
+ 'avg',
121
+ 'count',
122
+ 'count_distinct',
123
+ 'min',
124
+ 'max',
125
+ 'variance',
126
+ 'variance_pop',
127
+ 'stddev',
128
+ 'median',
129
+ 'quantile'
130
+ ];
131
+ const isAggregateFunction = (func)=>AGGREGATE_FUNCTIONS.includes(func);
132
+ const toAggregateExpression = (func, field, aggr)=>{
133
+ switch(func){
134
+ case 'count':
135
+ return external_kysely_sql`count(${external_kysely_sql.ref(field)})`;
136
+ case 'count_distinct':
137
+ return external_kysely_sql`count(distinct ${external_kysely_sql.ref(field)})`;
138
+ case 'variance':
139
+ return external_kysely_sql`var_samp(${external_kysely_sql.ref(field)})`;
140
+ case 'variance_pop':
141
+ return external_kysely_sql`var_pop(${external_kysely_sql.ref(field)})`;
142
+ case 'quantile':
143
+ return external_kysely_sql`quantile(${external_kysely_sql.ref(field)}, ${aggr?.quantile ?? 0.5})`;
144
+ default:
145
+ return external_kysely_sql`${external_kysely_sql.raw(func)}(${external_kysely_sql.ref(field)})`;
146
+ }
147
+ };
118
148
  const applyHaving = (qb, having)=>{
119
149
  if (!having) return qb;
120
150
  const toRaw = (h)=>{
@@ -126,48 +156,40 @@ const applyHaving = (qb, having)=>{
126
156
  const leaf = h;
127
157
  const field = leaf.field;
128
158
  const value = leaf.value;
129
- const op = toSqlOperator(leaf.op);
130
- if ([
131
- 'sum',
132
- 'avg',
133
- 'count',
134
- 'min',
135
- 'max'
136
- ].includes(op)) {
137
- const aggrExpr = external_kysely_sql`${external_kysely_sql.raw(op.toLowerCase())}(${external_kysely_sql.ref(field)})`;
138
- return external_kysely_sql`${aggrExpr} = ${external_kysely_sql.val(value)}`;
139
- }
140
- switch(leaf.op){
159
+ if (!leaf.aggr?.func || !isAggregateFunction(leaf.aggr.func)) throw new Error(`Invalid having clause for field "${String(field)}": aggr.func is required`);
160
+ const compareOp = toSqlOperator(leaf.op.trim().toLowerCase());
161
+ const leftExpr = toAggregateExpression(leaf.aggr.func, field, leaf.aggr);
162
+ switch(compareOp){
141
163
  case 'is null':
142
- return external_kysely_sql`${external_kysely_sql.ref(field)} is null`;
164
+ return external_kysely_sql`${leftExpr} is null`;
143
165
  case 'is not null':
144
- return external_kysely_sql`${external_kysely_sql.ref(field)} is not null`;
166
+ return external_kysely_sql`${leftExpr} is not null`;
145
167
  case 'in':
146
168
  {
147
169
  const items = Array.isArray(value) ? value : [
148
170
  value
149
171
  ];
150
- return external_kysely_sql`${external_kysely_sql.ref(field)} in (${external_kysely_sql.join(items.map((v)=>external_kysely_sql.val(v)))})`;
172
+ return external_kysely_sql`${leftExpr} in (${external_kysely_sql.join(items.map((v)=>external_kysely_sql.val(v)))})`;
151
173
  }
152
174
  case 'not in':
153
175
  {
154
176
  const items = Array.isArray(value) ? value : [
155
177
  value
156
178
  ];
157
- return external_kysely_sql`not ${external_kysely_sql.ref(field)} in (${external_kysely_sql.join(items.map((v)=>external_kysely_sql.val(v)))})`;
179
+ return external_kysely_sql`not ${leftExpr} in (${external_kysely_sql.join(items.map((v)=>external_kysely_sql.val(v)))})`;
158
180
  }
159
181
  case 'between':
160
182
  {
161
183
  const [a, b] = value;
162
- return external_kysely_sql`${external_kysely_sql.ref(field)} between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
184
+ return external_kysely_sql`${leftExpr} between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
163
185
  }
164
186
  case 'not between':
165
187
  {
166
188
  const [a, b] = value;
167
- return external_kysely_sql`${external_kysely_sql.ref(field)} not between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
189
+ return external_kysely_sql`${leftExpr} not between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
168
190
  }
169
191
  default:
170
- return external_kysely_sql`${external_kysely_sql.ref(field)} ${external_kysely_sql.raw(op)} ${external_kysely_sql.val(value)}`;
192
+ return external_kysely_sql`${leftExpr} ${external_kysely_sql.raw(compareOp)} ${external_kysely_sql.val(value)}`;
171
193
  }
172
194
  };
173
195
  return qb.having(toRaw(having));
@@ -205,12 +227,12 @@ const applySelect = (qb, select)=>{
205
227
  'min',
206
228
  'max',
207
229
  'variance',
208
- 'variancePop',
230
+ 'variance_pop',
209
231
  'stddev',
210
232
  'median'
211
233
  ].includes(func)) {
212
234
  if ('variance' === func) return external_kysely_sql`var_samp(${expression})`.as(alias);
213
- if ('variancePop' === func) return external_kysely_sql`var_pop(${expression})`.as(alias);
235
+ if ('variance_pop' === func) return external_kysely_sql`var_pop(${expression})`.as(alias);
214
236
  return external_kysely_sql`${external_kysely_sql.raw(func)}(${expression})`.as(alias);
215
237
  }
216
238
  if ('count' === func) return external_kysely_sql`CAST(count(${expression}) AS INTEGER)`.as(alias);
@@ -1,3 +1,3 @@
1
1
  import type { SelectQueryBuilder } from 'kysely';
2
- import { Having, HavingClause } from '../../types';
2
+ import type { Having, HavingClause } from '../../types';
3
3
  export declare const applyHaving: <DB, TB extends keyof DB & string, O, T>(qb: SelectQueryBuilder<DB, TB, O>, having?: Having<T> | HavingClause<T>) => SelectQueryBuilder<DB, TB, O>;
@@ -2,6 +2,7 @@
2
2
  * Having 子句类型定义
3
3
  * 用于聚合后的数据筛选
4
4
  */
5
+ import type { BaseAggregateFunction } from './Select';
5
6
  export type Having<T> = HavingGroup<T>;
6
7
  export type HavingGroup<T> = {
7
8
  op: 'and' | 'or';
@@ -10,13 +11,14 @@ export type HavingGroup<T> = {
10
11
  export type HavingClause<T> = HavingLeaf<T> | HavingGroup<T>;
11
12
  /**
12
13
  * Having 叶子节点
13
- * 支持聚合函数操作符
14
+ * 通过 aggr 指定聚合方式,通过 op 指定比较操作符
14
15
  */
15
16
  export type HavingLeaf<T> = {
16
17
  [K in keyof T]: {
17
- [O in HavingOperator]: {
18
+ [O in HavingComparisonOperator]: {
18
19
  field: K;
19
20
  op: O;
21
+ aggr: HavingAggregation;
20
22
  } & (O extends 'is null' | 'is not null' ? {
21
23
  value?: never;
22
24
  } : O extends 'in' | 'not in' ? {
@@ -26,10 +28,21 @@ export type HavingLeaf<T> = {
26
28
  } : {
27
29
  value: T[K];
28
30
  });
29
- }[HavingOperator];
31
+ }[HavingComparisonOperator];
30
32
  }[keyof T];
31
33
  /**
32
- * Having 操作符
33
- * 聚合函数操作符
34
+ * Having 聚合函数
34
35
  */
35
- export type HavingOperator = 'sum' | 'avg' | 'count' | 'min' | 'max' | '=' | '!=' | '>' | '>=' | '<' | '<=' | 'between' | 'not between' | 'in' | 'not in' | 'is null' | 'is not null';
36
+ export type HavingAggregateFunction = BaseAggregateFunction;
37
+ export type HavingAggregation = {
38
+ func: HavingAggregateFunction;
39
+ quantile?: number;
40
+ };
41
+ /**
42
+ * Having 比较操作符
43
+ */
44
+ export type HavingComparisonOperator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'between' | 'not between' | 'in' | 'not in' | 'is null' | 'is not null';
45
+ /**
46
+ * Having 操作符(仅比较操作符)
47
+ */
48
+ export type HavingOperator = HavingComparisonOperator;
@@ -1,4 +1,4 @@
1
- export type BaseAggregateFunction = 'count' | 'count_distinct' | 'sum' | 'avg' | 'min' | 'max' | 'variance' | 'variancePop' | 'stddev' | 'median' | 'quantile';
1
+ export type BaseAggregateFunction = 'count' | 'count_distinct' | 'sum' | 'avg' | 'min' | 'max' | 'variance' | 'variance_pop' | 'stddev' | 'median' | 'quantile';
2
2
  export type DateAggregateFunction = 'to_year' | 'to_quarter' | 'to_month' | 'to_week' | 'to_day' | 'to_hour' | 'to_minute' | 'to_second';
3
3
  export type AggregateFunction = BaseAggregateFunction | DateAggregateFunction;
4
4
  export type SelectItem<T> = {
@@ -3,4 +3,4 @@ export type { GroupBy } from './GroupBy';
3
3
  export type { OrderBy } from './OrderBy';
4
4
  export type { Select } from './Select';
5
5
  export type { Where, WhereClause, WhereLeaf, WhereGroup } from './Where';
6
- export type { Having, HavingClause, HavingLeaf, HavingGroup, HavingOperator } from './Having';
6
+ export type { Having, HavingClause, HavingLeaf, HavingGroup, HavingOperator, HavingAggregation, HavingAggregateFunction, HavingComparisonOperator, } from './Having';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visactor/vquery",
3
- "version": "0.4.16",
3
+ "version": "0.4.19",
4
4
  "license": "MIT",
5
5
  "homepage": "https://visactor.github.io/VBI",
6
6
  "bugs": "https://github.com/VisActor/VBI/issues",