@visactor/vquery 0.4.9 → 0.4.11

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.
@@ -51,7 +51,17 @@ const inlineParameters = (sql, params)=>{
51
51
  });
52
52
  return sql;
53
53
  };
54
- const applyWhere = (where)=>{
54
+ const operatorMap = {
55
+ gt: '>',
56
+ gte: '>=',
57
+ lt: '<',
58
+ lte: '<=',
59
+ eq: '=',
60
+ neq: '!='
61
+ };
62
+ const toSqlOperator = (op)=>operatorMap[op] ?? op;
63
+ const applyWhere = (qb, where)=>{
64
+ if (!where) return qb;
55
65
  const toRaw = (w)=>{
56
66
  if ('op' in w && 'conditions' in w) {
57
67
  const parts = w.conditions.map((c)=>toRaw(c));
@@ -61,6 +71,7 @@ const applyWhere = (where)=>{
61
71
  const leaf = w;
62
72
  const field = leaf.field;
63
73
  const value = leaf.value;
74
+ const sqlOp = toSqlOperator(leaf.op);
64
75
  switch(leaf.op){
65
76
  case 'is null':
66
77
  return external_kysely_sql`${external_kysely_sql.ref(field)} is null`;
@@ -91,10 +102,10 @@ const applyWhere = (where)=>{
91
102
  return external_kysely_sql`${external_kysely_sql.ref(field)} not between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
92
103
  }
93
104
  default:
94
- return external_kysely_sql`${external_kysely_sql.ref(field)} ${external_kysely_sql.raw(leaf.op)} ${external_kysely_sql.val(value)}`;
105
+ return external_kysely_sql`${external_kysely_sql.ref(field)} ${external_kysely_sql.raw(sqlOp)} ${external_kysely_sql.val(value)}`;
95
106
  }
96
107
  };
97
- return toRaw(where);
108
+ return qb.where(toRaw(where));
98
109
  };
99
110
  const applyGroupBy = (qb, fields)=>{
100
111
  if (fields && fields.length > 0) {
@@ -103,60 +114,17 @@ const applyGroupBy = (qb, fields)=>{
103
114
  }
104
115
  return qb;
105
116
  };
106
- const applyLimit = (qb, limit)=>{
107
- if (limit && 'number' == typeof limit) qb = qb.limit(limit);
108
- return qb;
109
- };
110
- const DATE_FORMAT_MAP = {
111
- year: '%Y',
112
- month: '%Y-%m',
113
- day: '%Y-%m-%d',
114
- week: '%Y-W%W',
115
- hour: '%Y-%m-%d %H',
116
- minute: '%Y-%m-%d %H:%M',
117
- second: '%Y-%m-%d %H:%M:%S'
117
+ const having_operatorMap = {
118
+ gt: '>',
119
+ gte: '>=',
120
+ lt: '<',
121
+ lte: '<=',
122
+ eq: '=',
123
+ neq: '!='
118
124
  };
119
- const applySelect = (qb, select)=>{
120
- if (select && select.length > 0) return qb.select((eb)=>select.map((item)=>{
121
- if (isSelectItem(item)) {
122
- const field = item.field;
123
- const expression = eb.ref(field);
124
- if (item.aggr) {
125
- const { func } = item.aggr;
126
- const sqlAlias = field;
127
- if ([
128
- 'avg',
129
- 'sum',
130
- 'min',
131
- 'max',
132
- 'variance',
133
- 'variancePop',
134
- 'stddev',
135
- 'median'
136
- ].includes(func)) {
137
- if ('variance' === func) return external_kysely_sql`var_samp(${expression})`.as(sqlAlias);
138
- if ('variancePop' === func) return external_kysely_sql`var_pop(${expression})`.as(sqlAlias);
139
- return external_kysely_sql`${external_kysely_sql.raw(func)}(${expression})`.as(sqlAlias);
140
- }
141
- if ('count' === func) return external_kysely_sql`CAST(count(${expression}) AS INTEGER)`.as(sqlAlias);
142
- if ('quantile' === func) {
143
- const q = item.aggr.quantile ?? 0.5;
144
- return external_kysely_sql`quantile(${expression}, ${q})`.as(sqlAlias);
145
- } else if ('count_distinct' === func) return external_kysely_sql`CAST(count(distinct ${expression}) AS INTEGER)`.as(sqlAlias);
146
- else if (func.startsWith('to_')) {
147
- const dateTrunc = func.replace('to_', '');
148
- const format = DATE_FORMAT_MAP[dateTrunc];
149
- if (format) return external_kysely_sql`strftime(CAST(${expression} AS TIMESTAMP), ${format})`.as(sqlAlias);
150
- if ('quarter' === dateTrunc) return external_kysely_sql`strftime(CAST(${expression} AS TIMESTAMP), '%Y') || '-Q' || date_part('quarter', CAST(${expression} AS TIMESTAMP))`.as(sqlAlias);
151
- }
152
- }
153
- return expression.as(field);
154
- }
155
- return item;
156
- }));
157
- return qb.selectAll();
158
- };
159
- const applyHaving = (having)=>{
125
+ const having_toSqlOperator = (op)=>having_operatorMap[op] ?? op;
126
+ const applyHaving = (qb, having)=>{
127
+ if (!having) return qb;
160
128
  const toRaw = (h)=>{
161
129
  if ('op' in h && 'conditions' in h) {
162
130
  const parts = h.conditions.map((c)=>toRaw(c));
@@ -166,7 +134,7 @@ const applyHaving = (having)=>{
166
134
  const leaf = h;
167
135
  const field = leaf.field;
168
136
  const value = leaf.value;
169
- const op = leaf.op;
137
+ const op = having_toSqlOperator(leaf.op);
170
138
  if ([
171
139
  'sum',
172
140
  'avg',
@@ -177,7 +145,7 @@ const applyHaving = (having)=>{
177
145
  const aggrExpr = external_kysely_sql`${external_kysely_sql.raw(op.toLowerCase())}(${external_kysely_sql.ref(field)})`;
178
146
  return external_kysely_sql`${aggrExpr} = ${external_kysely_sql.val(value)}`;
179
147
  }
180
- switch(op){
148
+ switch(leaf.op){
181
149
  case 'is null':
182
150
  return external_kysely_sql`${external_kysely_sql.ref(field)} is null`;
183
151
  case 'is not null':
@@ -210,22 +178,66 @@ const applyHaving = (having)=>{
210
178
  return external_kysely_sql`${external_kysely_sql.ref(field)} ${external_kysely_sql.raw(op)} ${external_kysely_sql.val(value)}`;
211
179
  }
212
180
  };
213
- return toRaw(having);
181
+ return qb.having(toRaw(having));
214
182
  };
215
- const resolveHavingAliases = (having, aliasToFieldMap)=>{
216
- if (!having) return having;
217
- if ('op' in having && 'conditions' in having) return {
218
- ...having,
219
- conditions: having.conditions.map((c)=>resolveHavingAliases(c, aliasToFieldMap))
220
- };
221
- if ('field' in having) {
222
- const resolvedField = aliasToFieldMap[having.field] || having.field;
223
- return {
224
- ...having,
225
- field: resolvedField
226
- };
227
- }
228
- return having;
183
+ const applyLimit = (qb, limit)=>{
184
+ if (limit && 'number' == typeof limit) qb = qb.limit(limit);
185
+ return qb;
186
+ };
187
+ const applyOrder = (qb, orderBy)=>{
188
+ if (orderBy && orderBy.length > 0) orderBy.forEach((o)=>{
189
+ qb = qb.orderBy(o.field, o.order ?? 'asc');
190
+ });
191
+ return qb;
192
+ };
193
+ const DATE_FORMAT_MAP = {
194
+ year: '%Y',
195
+ month: '%Y-%m',
196
+ day: '%Y-%m-%d',
197
+ week: '%Y-W%W',
198
+ hour: '%Y-%m-%d %H',
199
+ minute: '%Y-%m-%d %H:%M',
200
+ second: '%Y-%m-%d %H:%M:%S'
201
+ };
202
+ const applySelect = (qb, select)=>{
203
+ if (select && select.length > 0) return qb.select((eb)=>select.map((item)=>{
204
+ if (isSelectItem(item)) {
205
+ const field = item.field;
206
+ const expression = eb.ref(field);
207
+ const alias = item.alias ?? field;
208
+ if (item.aggr) {
209
+ const { func } = item.aggr;
210
+ if ([
211
+ 'avg',
212
+ 'sum',
213
+ 'min',
214
+ 'max',
215
+ 'variance',
216
+ 'variancePop',
217
+ 'stddev',
218
+ 'median'
219
+ ].includes(func)) {
220
+ if ('variance' === func) return external_kysely_sql`var_samp(${expression})`.as(alias);
221
+ if ('variancePop' === func) return external_kysely_sql`var_pop(${expression})`.as(alias);
222
+ return external_kysely_sql`${external_kysely_sql.raw(func)}(${expression})`.as(alias);
223
+ }
224
+ if ('count' === func) return external_kysely_sql`CAST(count(${expression}) AS INTEGER)`.as(alias);
225
+ if ('quantile' === func) {
226
+ const q = item.aggr.quantile ?? 0.5;
227
+ return external_kysely_sql`quantile(${expression}, ${q})`.as(alias);
228
+ } else if ('count_distinct' === func) return external_kysely_sql`CAST(count(distinct ${expression}) AS INTEGER)`.as(alias);
229
+ else if (func.startsWith('to_')) {
230
+ const dateTrunc = func.replace('to_', '');
231
+ const format = DATE_FORMAT_MAP[dateTrunc];
232
+ if (format) return external_kysely_sql`strftime(CAST(${expression} AS TIMESTAMP), ${format})`.as(alias);
233
+ if ('quarter' === dateTrunc) return external_kysely_sql`strftime(CAST(${expression} AS TIMESTAMP), '%Y') || '-Q' || date_part('quarter', CAST(${expression} AS TIMESTAMP))`.as(alias);
234
+ }
235
+ }
236
+ return expression.as(alias);
237
+ }
238
+ return item;
239
+ }));
240
+ return qb.selectAll();
229
241
  };
230
242
  const convertDSLToSQL = (dsl, tableName)=>{
231
243
  const db = new Kysely({
@@ -233,30 +245,13 @@ const convertDSLToSQL = (dsl, tableName)=>{
233
245
  });
234
246
  let qb = db.selectFrom(tableName);
235
247
  qb = applySelect(qb, dsl.select);
236
- if (dsl.where) qb = qb.where(applyWhere(dsl.where));
237
- const aliasToFieldMap = {};
238
- if (dsl.select && Array.isArray(dsl.select)) {
239
- for (const item of dsl.select)if ('object' == typeof item && null !== item) {
240
- const field = item.field;
241
- const alias = item.alias;
242
- if (alias && field) aliasToFieldMap[alias] = field;
243
- }
244
- }
245
- let resolvedGroupBy = dsl.groupBy;
246
- if (dsl.groupBy && dsl.groupBy.length > 0) resolvedGroupBy = dsl.groupBy.map((g)=>aliasToFieldMap[g] || g);
247
- qb = applyGroupBy(qb, resolvedGroupBy);
248
- if (dsl.having) {
249
- const resolvedHaving = resolveHavingAliases(dsl.having, aliasToFieldMap);
250
- qb = qb.having(applyHaving(resolvedHaving));
251
- }
252
- if (dsl.orderBy && dsl.orderBy.length > 0) for (const o of dsl.orderBy){
253
- const fieldStr = o.field;
254
- const resolvedField = aliasToFieldMap[fieldStr] || fieldStr;
255
- qb = qb.orderBy(resolvedField, o.order ?? 'asc');
256
- }
248
+ qb = applyWhere(qb, dsl.where);
249
+ qb = applyGroupBy(qb, dsl.groupBy);
250
+ qb = applyHaving(qb, dsl.having);
251
+ qb = applyOrder(qb, dsl.orderBy);
257
252
  qb = applyLimit(qb, dsl.limit);
258
- const compiled = qb.compile();
259
- return inlineParameters(compiled.sql, compiled.parameters);
253
+ const { sql, parameters } = qb.compile();
254
+ return inlineParameters(sql, parameters);
260
255
  };
261
256
  const READ_FUNCTION_MAP = {
262
257
  csv: 'read_csv_auto',
@@ -1,3 +1,3 @@
1
+ import type { SelectQueryBuilder } from 'kysely';
1
2
  import { Having, HavingClause } from '../../types';
2
- import type { RawBuilder } from 'kysely';
3
- export declare const applyHaving: <T>(having: Having<T> | HavingClause<T>) => RawBuilder<boolean>;
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>;
@@ -1,5 +1,6 @@
1
1
  export { applyWhere } from './where';
2
2
  export { applyGroupBy } from './groupBy';
3
+ export { applyHaving } from './having';
3
4
  export { applyLimit } from './limit';
5
+ export { applyOrder } from './order';
4
6
  export { applySelect } from './select';
5
- export { applyHaving } from './having';
@@ -0,0 +1,7 @@
1
+ import type { SelectQueryBuilder } from 'kysely';
2
+ type OrderByItem = {
3
+ field: string;
4
+ order?: 'asc' | 'desc';
5
+ };
6
+ export declare const applyOrder: <DB, TB extends keyof DB & string, O>(qb: SelectQueryBuilder<DB, TB, O>, orderBy?: Array<OrderByItem>) => SelectQueryBuilder<DB, TB, O>;
7
+ export {};
@@ -1,3 +1,3 @@
1
1
  import { Where, WhereClause } from '../../types';
2
- import type { RawBuilder } from 'kysely';
3
- export declare const applyWhere: <T>(where: Where<T> | WhereClause<T>) => RawBuilder<boolean>;
2
+ import type { SelectQueryBuilder } from 'kysely';
3
+ export declare const applyWhere: <DB, TB extends keyof DB & string, O, T>(qb: SelectQueryBuilder<DB, TB, O>, where?: Where<T> | WhereClause<T>) => SelectQueryBuilder<DB, TB, O>;
@@ -1,2 +1,2 @@
1
- import { QueryDSL, VQueryDSL } from '../types';
1
+ import type { QueryDSL, VQueryDSL } from '../types';
2
2
  export declare const convertDSLToSQL: <T, TableName extends string>(dsl: QueryDSL<T> | VQueryDSL<T>, tableName: TableName) => string;
@@ -1,8 +1,8 @@
1
1
  import { GroupBy } from './GroupBy';
2
+ import { Having } from './Having';
2
3
  import { OrderBy } from './OrderBy';
3
4
  import { Select } from './Select';
4
5
  import { Where } from './Where';
5
- import { Having } from './Having';
6
6
  export interface QueryDSL<Table> {
7
7
  select: Select<Table>;
8
8
  where?: Where<Table>;
@@ -89,7 +89,17 @@ const inlineParameters = (sql, params)=>{
89
89
  });
90
90
  return sql;
91
91
  };
92
- const applyWhere = (where)=>{
92
+ const operatorMap = {
93
+ gt: '>',
94
+ gte: '>=',
95
+ lt: '<',
96
+ lte: '<=',
97
+ eq: '=',
98
+ neq: '!='
99
+ };
100
+ const toSqlOperator = (op)=>operatorMap[op] ?? op;
101
+ const applyWhere = (qb, where)=>{
102
+ if (!where) return qb;
93
103
  const toRaw = (w)=>{
94
104
  if ('op' in w && 'conditions' in w) {
95
105
  const parts = w.conditions.map((c)=>toRaw(c));
@@ -99,6 +109,7 @@ const applyWhere = (where)=>{
99
109
  const leaf = w;
100
110
  const field = leaf.field;
101
111
  const value = leaf.value;
112
+ const sqlOp = toSqlOperator(leaf.op);
102
113
  switch(leaf.op){
103
114
  case 'is null':
104
115
  return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} is null`;
@@ -129,10 +140,10 @@ const applyWhere = (where)=>{
129
140
  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)}`;
130
141
  }
131
142
  default:
132
- return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} ${external_kysely_namespaceObject.sql.raw(leaf.op)} ${external_kysely_namespaceObject.sql.val(value)}`;
143
+ return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} ${external_kysely_namespaceObject.sql.raw(sqlOp)} ${external_kysely_namespaceObject.sql.val(value)}`;
133
144
  }
134
145
  };
135
- return toRaw(where);
146
+ return qb.where(toRaw(where));
136
147
  };
137
148
  const applyGroupBy = (qb, fields)=>{
138
149
  if (fields && fields.length > 0) {
@@ -141,60 +152,17 @@ const applyGroupBy = (qb, fields)=>{
141
152
  }
142
153
  return qb;
143
154
  };
144
- const applyLimit = (qb, limit)=>{
145
- if (limit && 'number' == typeof limit) qb = qb.limit(limit);
146
- return qb;
147
- };
148
- const DATE_FORMAT_MAP = {
149
- year: '%Y',
150
- month: '%Y-%m',
151
- day: '%Y-%m-%d',
152
- week: '%Y-W%W',
153
- hour: '%Y-%m-%d %H',
154
- minute: '%Y-%m-%d %H:%M',
155
- second: '%Y-%m-%d %H:%M:%S'
155
+ const having_operatorMap = {
156
+ gt: '>',
157
+ gte: '>=',
158
+ lt: '<',
159
+ lte: '<=',
160
+ eq: '=',
161
+ neq: '!='
156
162
  };
157
- const applySelect = (qb, select)=>{
158
- if (select && select.length > 0) return qb.select((eb)=>select.map((item)=>{
159
- if (isSelectItem(item)) {
160
- const field = item.field;
161
- const expression = eb.ref(field);
162
- if (item.aggr) {
163
- const { func } = item.aggr;
164
- const sqlAlias = field;
165
- if ([
166
- 'avg',
167
- 'sum',
168
- 'min',
169
- 'max',
170
- 'variance',
171
- 'variancePop',
172
- 'stddev',
173
- 'median'
174
- ].includes(func)) {
175
- if ('variance' === func) return (0, external_kysely_namespaceObject.sql)`var_samp(${expression})`.as(sqlAlias);
176
- if ('variancePop' === func) return (0, external_kysely_namespaceObject.sql)`var_pop(${expression})`.as(sqlAlias);
177
- return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.raw(func)}(${expression})`.as(sqlAlias);
178
- }
179
- if ('count' === func) return (0, external_kysely_namespaceObject.sql)`CAST(count(${expression}) AS INTEGER)`.as(sqlAlias);
180
- if ('quantile' === func) {
181
- const q = item.aggr.quantile ?? 0.5;
182
- return (0, external_kysely_namespaceObject.sql)`quantile(${expression}, ${q})`.as(sqlAlias);
183
- } else if ('count_distinct' === func) return (0, external_kysely_namespaceObject.sql)`CAST(count(distinct ${expression}) AS INTEGER)`.as(sqlAlias);
184
- else if (func.startsWith('to_')) {
185
- const dateTrunc = func.replace('to_', '');
186
- const format = DATE_FORMAT_MAP[dateTrunc];
187
- if (format) return (0, external_kysely_namespaceObject.sql)`strftime(CAST(${expression} AS TIMESTAMP), ${format})`.as(sqlAlias);
188
- if ('quarter' === dateTrunc) return (0, external_kysely_namespaceObject.sql)`strftime(CAST(${expression} AS TIMESTAMP), '%Y') || '-Q' || date_part('quarter', CAST(${expression} AS TIMESTAMP))`.as(sqlAlias);
189
- }
190
- }
191
- return expression.as(field);
192
- }
193
- return item;
194
- }));
195
- return qb.selectAll();
196
- };
197
- const applyHaving = (having)=>{
163
+ const having_toSqlOperator = (op)=>having_operatorMap[op] ?? op;
164
+ const applyHaving = (qb, having)=>{
165
+ if (!having) return qb;
198
166
  const toRaw = (h)=>{
199
167
  if ('op' in h && 'conditions' in h) {
200
168
  const parts = h.conditions.map((c)=>toRaw(c));
@@ -204,7 +172,7 @@ const applyHaving = (having)=>{
204
172
  const leaf = h;
205
173
  const field = leaf.field;
206
174
  const value = leaf.value;
207
- const op = leaf.op;
175
+ const op = having_toSqlOperator(leaf.op);
208
176
  if ([
209
177
  'sum',
210
178
  'avg',
@@ -215,7 +183,7 @@ const applyHaving = (having)=>{
215
183
  const aggrExpr = (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.raw(op.toLowerCase())}(${external_kysely_namespaceObject.sql.ref(field)})`;
216
184
  return (0, external_kysely_namespaceObject.sql)`${aggrExpr} = ${external_kysely_namespaceObject.sql.val(value)}`;
217
185
  }
218
- switch(op){
186
+ switch(leaf.op){
219
187
  case 'is null':
220
188
  return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} is null`;
221
189
  case 'is not null':
@@ -248,22 +216,66 @@ const applyHaving = (having)=>{
248
216
  return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.ref(field)} ${external_kysely_namespaceObject.sql.raw(op)} ${external_kysely_namespaceObject.sql.val(value)}`;
249
217
  }
250
218
  };
251
- return toRaw(having);
219
+ return qb.having(toRaw(having));
252
220
  };
253
- const resolveHavingAliases = (having, aliasToFieldMap)=>{
254
- if (!having) return having;
255
- if ('op' in having && 'conditions' in having) return {
256
- ...having,
257
- conditions: having.conditions.map((c)=>resolveHavingAliases(c, aliasToFieldMap))
258
- };
259
- if ('field' in having) {
260
- const resolvedField = aliasToFieldMap[having.field] || having.field;
261
- return {
262
- ...having,
263
- field: resolvedField
264
- };
265
- }
266
- return having;
221
+ const applyLimit = (qb, limit)=>{
222
+ if (limit && 'number' == typeof limit) qb = qb.limit(limit);
223
+ return qb;
224
+ };
225
+ const applyOrder = (qb, orderBy)=>{
226
+ if (orderBy && orderBy.length > 0) orderBy.forEach((o)=>{
227
+ qb = qb.orderBy(o.field, o.order ?? 'asc');
228
+ });
229
+ return qb;
230
+ };
231
+ const DATE_FORMAT_MAP = {
232
+ year: '%Y',
233
+ month: '%Y-%m',
234
+ day: '%Y-%m-%d',
235
+ week: '%Y-W%W',
236
+ hour: '%Y-%m-%d %H',
237
+ minute: '%Y-%m-%d %H:%M',
238
+ second: '%Y-%m-%d %H:%M:%S'
239
+ };
240
+ const applySelect = (qb, select)=>{
241
+ if (select && select.length > 0) return qb.select((eb)=>select.map((item)=>{
242
+ if (isSelectItem(item)) {
243
+ const field = item.field;
244
+ const expression = eb.ref(field);
245
+ const alias = item.alias ?? field;
246
+ if (item.aggr) {
247
+ const { func } = item.aggr;
248
+ if ([
249
+ 'avg',
250
+ 'sum',
251
+ 'min',
252
+ 'max',
253
+ 'variance',
254
+ 'variancePop',
255
+ 'stddev',
256
+ 'median'
257
+ ].includes(func)) {
258
+ if ('variance' === func) return (0, external_kysely_namespaceObject.sql)`var_samp(${expression})`.as(alias);
259
+ if ('variancePop' === func) return (0, external_kysely_namespaceObject.sql)`var_pop(${expression})`.as(alias);
260
+ return (0, external_kysely_namespaceObject.sql)`${external_kysely_namespaceObject.sql.raw(func)}(${expression})`.as(alias);
261
+ }
262
+ if ('count' === func) return (0, external_kysely_namespaceObject.sql)`CAST(count(${expression}) AS INTEGER)`.as(alias);
263
+ if ('quantile' === func) {
264
+ const q = item.aggr.quantile ?? 0.5;
265
+ return (0, external_kysely_namespaceObject.sql)`quantile(${expression}, ${q})`.as(alias);
266
+ } else if ('count_distinct' === func) return (0, external_kysely_namespaceObject.sql)`CAST(count(distinct ${expression}) AS INTEGER)`.as(alias);
267
+ else if (func.startsWith('to_')) {
268
+ const dateTrunc = func.replace('to_', '');
269
+ const format = DATE_FORMAT_MAP[dateTrunc];
270
+ if (format) return (0, external_kysely_namespaceObject.sql)`strftime(CAST(${expression} AS TIMESTAMP), ${format})`.as(alias);
271
+ if ('quarter' === dateTrunc) return (0, external_kysely_namespaceObject.sql)`strftime(CAST(${expression} AS TIMESTAMP), '%Y') || '-Q' || date_part('quarter', CAST(${expression} AS TIMESTAMP))`.as(alias);
272
+ }
273
+ }
274
+ return expression.as(alias);
275
+ }
276
+ return item;
277
+ }));
278
+ return qb.selectAll();
267
279
  };
268
280
  const convertDSLToSQL = (dsl, tableName)=>{
269
281
  const db = new external_kysely_namespaceObject.Kysely({
@@ -271,30 +283,13 @@ const convertDSLToSQL = (dsl, tableName)=>{
271
283
  });
272
284
  let qb = db.selectFrom(tableName);
273
285
  qb = applySelect(qb, dsl.select);
274
- if (dsl.where) qb = qb.where(applyWhere(dsl.where));
275
- const aliasToFieldMap = {};
276
- if (dsl.select && Array.isArray(dsl.select)) {
277
- for (const item of dsl.select)if ('object' == typeof item && null !== item) {
278
- const field = item.field;
279
- const alias = item.alias;
280
- if (alias && field) aliasToFieldMap[alias] = field;
281
- }
282
- }
283
- let resolvedGroupBy = dsl.groupBy;
284
- if (dsl.groupBy && dsl.groupBy.length > 0) resolvedGroupBy = dsl.groupBy.map((g)=>aliasToFieldMap[g] || g);
285
- qb = applyGroupBy(qb, resolvedGroupBy);
286
- if (dsl.having) {
287
- const resolvedHaving = resolveHavingAliases(dsl.having, aliasToFieldMap);
288
- qb = qb.having(applyHaving(resolvedHaving));
289
- }
290
- if (dsl.orderBy && dsl.orderBy.length > 0) for (const o of dsl.orderBy){
291
- const fieldStr = o.field;
292
- const resolvedField = aliasToFieldMap[fieldStr] || fieldStr;
293
- qb = qb.orderBy(resolvedField, o.order ?? 'asc');
294
- }
286
+ qb = applyWhere(qb, dsl.where);
287
+ qb = applyGroupBy(qb, dsl.groupBy);
288
+ qb = applyHaving(qb, dsl.having);
289
+ qb = applyOrder(qb, dsl.orderBy);
295
290
  qb = applyLimit(qb, dsl.limit);
296
- const compiled = qb.compile();
297
- return inlineParameters(compiled.sql, compiled.parameters);
291
+ const { sql, parameters } = qb.compile();
292
+ return inlineParameters(sql, parameters);
298
293
  };
299
294
  const READ_FUNCTION_MAP = {
300
295
  csv: 'read_csv_auto',
@@ -1,3 +1,3 @@
1
+ import type { SelectQueryBuilder } from 'kysely';
1
2
  import { Having, HavingClause } from '../../types';
2
- import type { RawBuilder } from 'kysely';
3
- export declare const applyHaving: <T>(having: Having<T> | HavingClause<T>) => RawBuilder<boolean>;
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>;
@@ -1,5 +1,6 @@
1
1
  export { applyWhere } from './where';
2
2
  export { applyGroupBy } from './groupBy';
3
+ export { applyHaving } from './having';
3
4
  export { applyLimit } from './limit';
5
+ export { applyOrder } from './order';
4
6
  export { applySelect } from './select';
5
- export { applyHaving } from './having';
@@ -0,0 +1,7 @@
1
+ import type { SelectQueryBuilder } from 'kysely';
2
+ type OrderByItem = {
3
+ field: string;
4
+ order?: 'asc' | 'desc';
5
+ };
6
+ export declare const applyOrder: <DB, TB extends keyof DB & string, O>(qb: SelectQueryBuilder<DB, TB, O>, orderBy?: Array<OrderByItem>) => SelectQueryBuilder<DB, TB, O>;
7
+ export {};
@@ -1,3 +1,3 @@
1
1
  import { Where, WhereClause } from '../../types';
2
- import type { RawBuilder } from 'kysely';
3
- export declare const applyWhere: <T>(where: Where<T> | WhereClause<T>) => RawBuilder<boolean>;
2
+ import type { SelectQueryBuilder } from 'kysely';
3
+ export declare const applyWhere: <DB, TB extends keyof DB & string, O, T>(qb: SelectQueryBuilder<DB, TB, O>, where?: Where<T> | WhereClause<T>) => SelectQueryBuilder<DB, TB, O>;
@@ -1,2 +1,2 @@
1
- import { QueryDSL, VQueryDSL } from '../types';
1
+ import type { QueryDSL, VQueryDSL } from '../types';
2
2
  export declare const convertDSLToSQL: <T, TableName extends string>(dsl: QueryDSL<T> | VQueryDSL<T>, tableName: TableName) => string;
@@ -1,8 +1,8 @@
1
1
  import { GroupBy } from './GroupBy';
2
+ import { Having } from './Having';
2
3
  import { OrderBy } from './OrderBy';
3
4
  import { Select } from './Select';
4
5
  import { Where } from './Where';
5
- import { Having } from './Having';
6
6
  export interface QueryDSL<Table> {
7
7
  select: Select<Table>;
8
8
  where?: Where<Table>;
@@ -52,7 +52,17 @@ const inlineParameters = (sql, params)=>{
52
52
  });
53
53
  return sql;
54
54
  };
55
- const applyWhere = (where)=>{
55
+ const operatorMap = {
56
+ gt: '>',
57
+ gte: '>=',
58
+ lt: '<',
59
+ lte: '<=',
60
+ eq: '=',
61
+ neq: '!='
62
+ };
63
+ const toSqlOperator = (op)=>operatorMap[op] ?? op;
64
+ const applyWhere = (qb, where)=>{
65
+ if (!where) return qb;
56
66
  const toRaw = (w)=>{
57
67
  if ('op' in w && 'conditions' in w) {
58
68
  const parts = w.conditions.map((c)=>toRaw(c));
@@ -62,6 +72,7 @@ const applyWhere = (where)=>{
62
72
  const leaf = w;
63
73
  const field = leaf.field;
64
74
  const value = leaf.value;
75
+ const sqlOp = toSqlOperator(leaf.op);
65
76
  switch(leaf.op){
66
77
  case 'is null':
67
78
  return external_kysely_sql`${external_kysely_sql.ref(field)} is null`;
@@ -92,10 +103,10 @@ const applyWhere = (where)=>{
92
103
  return external_kysely_sql`${external_kysely_sql.ref(field)} not between ${external_kysely_sql.val(a)} and ${external_kysely_sql.val(b)}`;
93
104
  }
94
105
  default:
95
- return external_kysely_sql`${external_kysely_sql.ref(field)} ${external_kysely_sql.raw(leaf.op)} ${external_kysely_sql.val(value)}`;
106
+ return external_kysely_sql`${external_kysely_sql.ref(field)} ${external_kysely_sql.raw(sqlOp)} ${external_kysely_sql.val(value)}`;
96
107
  }
97
108
  };
98
- return toRaw(where);
109
+ return qb.where(toRaw(where));
99
110
  };
100
111
  const applyGroupBy = (qb, fields)=>{
101
112
  if (fields && fields.length > 0) {
@@ -104,60 +115,17 @@ const applyGroupBy = (qb, fields)=>{
104
115
  }
105
116
  return qb;
106
117
  };
107
- const applyLimit = (qb, limit)=>{
108
- if (limit && 'number' == typeof limit) qb = qb.limit(limit);
109
- return qb;
110
- };
111
- const DATE_FORMAT_MAP = {
112
- year: '%Y',
113
- month: '%Y-%m',
114
- day: '%Y-%m-%d',
115
- week: '%Y-W%W',
116
- hour: '%Y-%m-%d %H',
117
- minute: '%Y-%m-%d %H:%M',
118
- second: '%Y-%m-%d %H:%M:%S'
118
+ const having_operatorMap = {
119
+ gt: '>',
120
+ gte: '>=',
121
+ lt: '<',
122
+ lte: '<=',
123
+ eq: '=',
124
+ neq: '!='
119
125
  };
120
- const applySelect = (qb, select)=>{
121
- if (select && select.length > 0) return qb.select((eb)=>select.map((item)=>{
122
- if (isSelectItem(item)) {
123
- const field = item.field;
124
- const expression = eb.ref(field);
125
- if (item.aggr) {
126
- const { func } = item.aggr;
127
- const sqlAlias = field;
128
- if ([
129
- 'avg',
130
- 'sum',
131
- 'min',
132
- 'max',
133
- 'variance',
134
- 'variancePop',
135
- 'stddev',
136
- 'median'
137
- ].includes(func)) {
138
- if ('variance' === func) return external_kysely_sql`var_samp(${expression})`.as(sqlAlias);
139
- if ('variancePop' === func) return external_kysely_sql`var_pop(${expression})`.as(sqlAlias);
140
- return external_kysely_sql`${external_kysely_sql.raw(func)}(${expression})`.as(sqlAlias);
141
- }
142
- if ('count' === func) return external_kysely_sql`CAST(count(${expression}) AS INTEGER)`.as(sqlAlias);
143
- if ('quantile' === func) {
144
- const q = item.aggr.quantile ?? 0.5;
145
- return external_kysely_sql`quantile(${expression}, ${q})`.as(sqlAlias);
146
- } else if ('count_distinct' === func) return external_kysely_sql`CAST(count(distinct ${expression}) AS INTEGER)`.as(sqlAlias);
147
- else if (func.startsWith('to_')) {
148
- const dateTrunc = func.replace('to_', '');
149
- const format = DATE_FORMAT_MAP[dateTrunc];
150
- if (format) return external_kysely_sql`strftime(CAST(${expression} AS TIMESTAMP), ${format})`.as(sqlAlias);
151
- if ('quarter' === dateTrunc) return external_kysely_sql`strftime(CAST(${expression} AS TIMESTAMP), '%Y') || '-Q' || date_part('quarter', CAST(${expression} AS TIMESTAMP))`.as(sqlAlias);
152
- }
153
- }
154
- return expression.as(field);
155
- }
156
- return item;
157
- }));
158
- return qb.selectAll();
159
- };
160
- const applyHaving = (having)=>{
126
+ const having_toSqlOperator = (op)=>having_operatorMap[op] ?? op;
127
+ const applyHaving = (qb, having)=>{
128
+ if (!having) return qb;
161
129
  const toRaw = (h)=>{
162
130
  if ('op' in h && 'conditions' in h) {
163
131
  const parts = h.conditions.map((c)=>toRaw(c));
@@ -167,7 +135,7 @@ const applyHaving = (having)=>{
167
135
  const leaf = h;
168
136
  const field = leaf.field;
169
137
  const value = leaf.value;
170
- const op = leaf.op;
138
+ const op = having_toSqlOperator(leaf.op);
171
139
  if ([
172
140
  'sum',
173
141
  'avg',
@@ -178,7 +146,7 @@ const applyHaving = (having)=>{
178
146
  const aggrExpr = external_kysely_sql`${external_kysely_sql.raw(op.toLowerCase())}(${external_kysely_sql.ref(field)})`;
179
147
  return external_kysely_sql`${aggrExpr} = ${external_kysely_sql.val(value)}`;
180
148
  }
181
- switch(op){
149
+ switch(leaf.op){
182
150
  case 'is null':
183
151
  return external_kysely_sql`${external_kysely_sql.ref(field)} is null`;
184
152
  case 'is not null':
@@ -211,22 +179,66 @@ const applyHaving = (having)=>{
211
179
  return external_kysely_sql`${external_kysely_sql.ref(field)} ${external_kysely_sql.raw(op)} ${external_kysely_sql.val(value)}`;
212
180
  }
213
181
  };
214
- return toRaw(having);
182
+ return qb.having(toRaw(having));
215
183
  };
216
- const resolveHavingAliases = (having, aliasToFieldMap)=>{
217
- if (!having) return having;
218
- if ('op' in having && 'conditions' in having) return {
219
- ...having,
220
- conditions: having.conditions.map((c)=>resolveHavingAliases(c, aliasToFieldMap))
221
- };
222
- if ('field' in having) {
223
- const resolvedField = aliasToFieldMap[having.field] || having.field;
224
- return {
225
- ...having,
226
- field: resolvedField
227
- };
228
- }
229
- return having;
184
+ const applyLimit = (qb, limit)=>{
185
+ if (limit && 'number' == typeof limit) qb = qb.limit(limit);
186
+ return qb;
187
+ };
188
+ const applyOrder = (qb, orderBy)=>{
189
+ if (orderBy && orderBy.length > 0) orderBy.forEach((o)=>{
190
+ qb = qb.orderBy(o.field, o.order ?? 'asc');
191
+ });
192
+ return qb;
193
+ };
194
+ const DATE_FORMAT_MAP = {
195
+ year: '%Y',
196
+ month: '%Y-%m',
197
+ day: '%Y-%m-%d',
198
+ week: '%Y-W%W',
199
+ hour: '%Y-%m-%d %H',
200
+ minute: '%Y-%m-%d %H:%M',
201
+ second: '%Y-%m-%d %H:%M:%S'
202
+ };
203
+ const applySelect = (qb, select)=>{
204
+ if (select && select.length > 0) return qb.select((eb)=>select.map((item)=>{
205
+ if (isSelectItem(item)) {
206
+ const field = item.field;
207
+ const expression = eb.ref(field);
208
+ const alias = item.alias ?? field;
209
+ if (item.aggr) {
210
+ const { func } = item.aggr;
211
+ if ([
212
+ 'avg',
213
+ 'sum',
214
+ 'min',
215
+ 'max',
216
+ 'variance',
217
+ 'variancePop',
218
+ 'stddev',
219
+ 'median'
220
+ ].includes(func)) {
221
+ if ('variance' === func) return external_kysely_sql`var_samp(${expression})`.as(alias);
222
+ if ('variancePop' === func) return external_kysely_sql`var_pop(${expression})`.as(alias);
223
+ return external_kysely_sql`${external_kysely_sql.raw(func)}(${expression})`.as(alias);
224
+ }
225
+ if ('count' === func) return external_kysely_sql`CAST(count(${expression}) AS INTEGER)`.as(alias);
226
+ if ('quantile' === func) {
227
+ const q = item.aggr.quantile ?? 0.5;
228
+ return external_kysely_sql`quantile(${expression}, ${q})`.as(alias);
229
+ } else if ('count_distinct' === func) return external_kysely_sql`CAST(count(distinct ${expression}) AS INTEGER)`.as(alias);
230
+ else if (func.startsWith('to_')) {
231
+ const dateTrunc = func.replace('to_', '');
232
+ const format = DATE_FORMAT_MAP[dateTrunc];
233
+ if (format) return external_kysely_sql`strftime(CAST(${expression} AS TIMESTAMP), ${format})`.as(alias);
234
+ if ('quarter' === dateTrunc) return external_kysely_sql`strftime(CAST(${expression} AS TIMESTAMP), '%Y') || '-Q' || date_part('quarter', CAST(${expression} AS TIMESTAMP))`.as(alias);
235
+ }
236
+ }
237
+ return expression.as(alias);
238
+ }
239
+ return item;
240
+ }));
241
+ return qb.selectAll();
230
242
  };
231
243
  const convertDSLToSQL = (dsl, tableName)=>{
232
244
  const db = new Kysely({
@@ -234,30 +246,13 @@ const convertDSLToSQL = (dsl, tableName)=>{
234
246
  });
235
247
  let qb = db.selectFrom(tableName);
236
248
  qb = applySelect(qb, dsl.select);
237
- if (dsl.where) qb = qb.where(applyWhere(dsl.where));
238
- const aliasToFieldMap = {};
239
- if (dsl.select && Array.isArray(dsl.select)) {
240
- for (const item of dsl.select)if ('object' == typeof item && null !== item) {
241
- const field = item.field;
242
- const alias = item.alias;
243
- if (alias && field) aliasToFieldMap[alias] = field;
244
- }
245
- }
246
- let resolvedGroupBy = dsl.groupBy;
247
- if (dsl.groupBy && dsl.groupBy.length > 0) resolvedGroupBy = dsl.groupBy.map((g)=>aliasToFieldMap[g] || g);
248
- qb = applyGroupBy(qb, resolvedGroupBy);
249
- if (dsl.having) {
250
- const resolvedHaving = resolveHavingAliases(dsl.having, aliasToFieldMap);
251
- qb = qb.having(applyHaving(resolvedHaving));
252
- }
253
- if (dsl.orderBy && dsl.orderBy.length > 0) for (const o of dsl.orderBy){
254
- const fieldStr = o.field;
255
- const resolvedField = aliasToFieldMap[fieldStr] || fieldStr;
256
- qb = qb.orderBy(resolvedField, o.order ?? 'asc');
257
- }
249
+ qb = applyWhere(qb, dsl.where);
250
+ qb = applyGroupBy(qb, dsl.groupBy);
251
+ qb = applyHaving(qb, dsl.having);
252
+ qb = applyOrder(qb, dsl.orderBy);
258
253
  qb = applyLimit(qb, dsl.limit);
259
- const compiled = qb.compile();
260
- return inlineParameters(compiled.sql, compiled.parameters);
254
+ const { sql, parameters } = qb.compile();
255
+ return inlineParameters(sql, parameters);
261
256
  };
262
257
  const READ_FUNCTION_MAP = {
263
258
  csv: 'read_csv_auto',
@@ -1,3 +1,3 @@
1
+ import type { SelectQueryBuilder } from 'kysely';
1
2
  import { Having, HavingClause } from '../../types';
2
- import type { RawBuilder } from 'kysely';
3
- export declare const applyHaving: <T>(having: Having<T> | HavingClause<T>) => RawBuilder<boolean>;
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>;
@@ -1,5 +1,6 @@
1
1
  export { applyWhere } from './where';
2
2
  export { applyGroupBy } from './groupBy';
3
+ export { applyHaving } from './having';
3
4
  export { applyLimit } from './limit';
5
+ export { applyOrder } from './order';
4
6
  export { applySelect } from './select';
5
- export { applyHaving } from './having';
@@ -0,0 +1,7 @@
1
+ import type { SelectQueryBuilder } from 'kysely';
2
+ type OrderByItem = {
3
+ field: string;
4
+ order?: 'asc' | 'desc';
5
+ };
6
+ export declare const applyOrder: <DB, TB extends keyof DB & string, O>(qb: SelectQueryBuilder<DB, TB, O>, orderBy?: Array<OrderByItem>) => SelectQueryBuilder<DB, TB, O>;
7
+ export {};
@@ -1,3 +1,3 @@
1
1
  import { Where, WhereClause } from '../../types';
2
- import type { RawBuilder } from 'kysely';
3
- export declare const applyWhere: <T>(where: Where<T> | WhereClause<T>) => RawBuilder<boolean>;
2
+ import type { SelectQueryBuilder } from 'kysely';
3
+ export declare const applyWhere: <DB, TB extends keyof DB & string, O, T>(qb: SelectQueryBuilder<DB, TB, O>, where?: Where<T> | WhereClause<T>) => SelectQueryBuilder<DB, TB, O>;
@@ -1,2 +1,2 @@
1
- import { QueryDSL, VQueryDSL } from '../types';
1
+ import type { QueryDSL, VQueryDSL } from '../types';
2
2
  export declare const convertDSLToSQL: <T, TableName extends string>(dsl: QueryDSL<T> | VQueryDSL<T>, tableName: TableName) => string;
@@ -1,8 +1,8 @@
1
1
  import { GroupBy } from './GroupBy';
2
+ import { Having } from './Having';
2
3
  import { OrderBy } from './OrderBy';
3
4
  import { Select } from './Select';
4
5
  import { Where } from './Where';
5
- import { Having } from './Having';
6
6
  export interface QueryDSL<Table> {
7
7
  select: Select<Table>;
8
8
  where?: Where<Table>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visactor/vquery",
3
- "version": "0.4.9",
3
+ "version": "0.4.11",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {