pqb 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/index.d.ts +3630 -0
  2. package/dist/index.esm.js +4587 -0
  3. package/dist/index.esm.js.map +1 -0
  4. package/dist/index.js +4691 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +59 -0
  7. package/rollup.config.js +35 -0
  8. package/src/adapter.test.ts +10 -0
  9. package/src/adapter.ts +171 -0
  10. package/src/columnSchema/array.ts +21 -0
  11. package/src/columnSchema/boolean.ts +10 -0
  12. package/src/columnSchema/columnType.test.ts +129 -0
  13. package/src/columnSchema/columnType.ts +77 -0
  14. package/src/columnSchema/columnTypes.ts +145 -0
  15. package/src/columnSchema/columnsSchema.test.ts +32 -0
  16. package/src/columnSchema/columnsSchema.ts +100 -0
  17. package/src/columnSchema/commonMethods.ts +130 -0
  18. package/src/columnSchema/dateTime.ts +104 -0
  19. package/src/columnSchema/enum.ts +13 -0
  20. package/src/columnSchema/index.ts +11 -0
  21. package/src/columnSchema/json/array.ts +55 -0
  22. package/src/columnSchema/json/discriminatedUnion.ts +91 -0
  23. package/src/columnSchema/json/enum.ts +29 -0
  24. package/src/columnSchema/json/instanceOf.ts +16 -0
  25. package/src/columnSchema/json/intersection.ts +23 -0
  26. package/src/columnSchema/json/lazy.ts +22 -0
  27. package/src/columnSchema/json/literal.ts +12 -0
  28. package/src/columnSchema/json/map.ts +29 -0
  29. package/src/columnSchema/json/nativeEnum.ts +30 -0
  30. package/src/columnSchema/json/nullable.ts +33 -0
  31. package/src/columnSchema/json/nullish.ts +30 -0
  32. package/src/columnSchema/json/object.ts +206 -0
  33. package/src/columnSchema/json/optional.ts +28 -0
  34. package/src/columnSchema/json/record.ts +40 -0
  35. package/src/columnSchema/json/scalarTypes.ts +117 -0
  36. package/src/columnSchema/json/set.ts +34 -0
  37. package/src/columnSchema/json/tuple.ts +40 -0
  38. package/src/columnSchema/json/typeBase.ts +202 -0
  39. package/src/columnSchema/json/union.ts +16 -0
  40. package/src/columnSchema/json.ts +64 -0
  41. package/src/columnSchema/number.ts +122 -0
  42. package/src/columnSchema/string.ts +222 -0
  43. package/src/columnSchema/utils.ts +27 -0
  44. package/src/common.ts +86 -0
  45. package/src/db.test.ts +67 -0
  46. package/src/db.ts +212 -0
  47. package/src/errors.ts +7 -0
  48. package/src/index.ts +18 -0
  49. package/src/operators.test.ts +608 -0
  50. package/src/operators.ts +177 -0
  51. package/src/query.ts +292 -0
  52. package/src/queryDataUtils.ts +50 -0
  53. package/src/queryMethods/aggregate.test.ts +583 -0
  54. package/src/queryMethods/aggregate.ts +878 -0
  55. package/src/queryMethods/callbacks.test.ts +69 -0
  56. package/src/queryMethods/callbacks.ts +55 -0
  57. package/src/queryMethods/clear.test.ts +64 -0
  58. package/src/queryMethods/clear.ts +58 -0
  59. package/src/queryMethods/columnInfo.test.ts +45 -0
  60. package/src/queryMethods/columnInfo.ts +67 -0
  61. package/src/queryMethods/delete.test.ts +135 -0
  62. package/src/queryMethods/delete.ts +50 -0
  63. package/src/queryMethods/for.test.ts +57 -0
  64. package/src/queryMethods/for.ts +99 -0
  65. package/src/queryMethods/from.test.ts +66 -0
  66. package/src/queryMethods/from.ts +58 -0
  67. package/src/queryMethods/get.test.ts +66 -0
  68. package/src/queryMethods/get.ts +88 -0
  69. package/src/queryMethods/having.test.ts +247 -0
  70. package/src/queryMethods/having.ts +99 -0
  71. package/src/queryMethods/insert.test.ts +555 -0
  72. package/src/queryMethods/insert.ts +453 -0
  73. package/src/queryMethods/join.test.ts +150 -0
  74. package/src/queryMethods/join.ts +508 -0
  75. package/src/queryMethods/json.test.ts +398 -0
  76. package/src/queryMethods/json.ts +259 -0
  77. package/src/queryMethods/log.test.ts +172 -0
  78. package/src/queryMethods/log.ts +123 -0
  79. package/src/queryMethods/queryMethods.test.ts +629 -0
  80. package/src/queryMethods/queryMethods.ts +428 -0
  81. package/src/queryMethods/select.test.ts +479 -0
  82. package/src/queryMethods/select.ts +249 -0
  83. package/src/queryMethods/then.ts +236 -0
  84. package/src/queryMethods/transaction.test.ts +66 -0
  85. package/src/queryMethods/transaction.ts +66 -0
  86. package/src/queryMethods/union.test.ts +59 -0
  87. package/src/queryMethods/union.ts +89 -0
  88. package/src/queryMethods/update.test.ts +417 -0
  89. package/src/queryMethods/update.ts +350 -0
  90. package/src/queryMethods/upsert.test.ts +56 -0
  91. package/src/queryMethods/upsert.ts +43 -0
  92. package/src/queryMethods/where.test.ts +1594 -0
  93. package/src/queryMethods/where.ts +450 -0
  94. package/src/queryMethods/window.test.ts +66 -0
  95. package/src/queryMethods/window.ts +108 -0
  96. package/src/queryMethods/with.test.ts +191 -0
  97. package/src/queryMethods/with.ts +92 -0
  98. package/src/quote.ts +36 -0
  99. package/src/relations.ts +194 -0
  100. package/src/sql/aggregate.ts +80 -0
  101. package/src/sql/columnInfo.ts +22 -0
  102. package/src/sql/common.ts +42 -0
  103. package/src/sql/delete.ts +41 -0
  104. package/src/sql/distinct.ts +19 -0
  105. package/src/sql/fromAndAs.ts +51 -0
  106. package/src/sql/having.ts +140 -0
  107. package/src/sql/index.ts +2 -0
  108. package/src/sql/insert.ts +102 -0
  109. package/src/sql/join.ts +242 -0
  110. package/src/sql/orderBy.ts +41 -0
  111. package/src/sql/select.ts +153 -0
  112. package/src/sql/toSql.ts +153 -0
  113. package/src/sql/truncate.ts +13 -0
  114. package/src/sql/types.ts +355 -0
  115. package/src/sql/update.ts +62 -0
  116. package/src/sql/where.ts +314 -0
  117. package/src/sql/window.ts +38 -0
  118. package/src/sql/with.ts +32 -0
  119. package/src/test-utils.ts +172 -0
  120. package/src/utils.ts +140 -0
  121. package/tsconfig.build.json +6 -0
  122. package/tsconfig.json +8 -0
@@ -0,0 +1,66 @@
1
+ import { expectQueryNotMutated, expectSql, User } from '../test-utils';
2
+ import { raw } from '../common';
3
+
4
+ describe('from', () => {
5
+ it('should accept string parameter', () => {
6
+ const q = User.all();
7
+ expectSql(q.from('profile').toSql(), `SELECT * FROM "profile"`);
8
+ expectQueryNotMutated(q);
9
+ });
10
+
11
+ it('should accept string parameter with respect to `as`', () => {
12
+ const q = User.all();
13
+ expectSql(
14
+ q.as('t').from('profile').toSql(),
15
+ `SELECT * FROM "profile" AS "t"`,
16
+ );
17
+ expectQueryNotMutated(q);
18
+ });
19
+
20
+ it('should accept raw parameter', () => {
21
+ const q = User.all();
22
+ expectSql(
23
+ q.as('t').from(raw('profile')).toSql(),
24
+ `SELECT * FROM profile AS "t"`,
25
+ );
26
+ expectQueryNotMutated(q);
27
+ });
28
+
29
+ it('should accept query parameter', () => {
30
+ const q = User.all();
31
+ expectSql(
32
+ q.select('name').from(User.select('name')).toSql(),
33
+ 'SELECT "user"."name" FROM (SELECT "user"."name" FROM "user") AS "user"',
34
+ );
35
+ expectQueryNotMutated(q);
36
+ });
37
+
38
+ it('accept `as` parameter', () => {
39
+ const q = User.all();
40
+ expectSql(
41
+ q.select('name').from(User.select('name'), 'wrapped').toSql(),
42
+ `
43
+ SELECT "wrapped"."name"
44
+ FROM (SELECT "user"."name" FROM "user") AS "wrapped"
45
+ `,
46
+ );
47
+ expectQueryNotMutated(q);
48
+ });
49
+
50
+ it('should not insert sub query and alias if provided query is simple', () => {
51
+ const q = User.all();
52
+ expectSql(
53
+ q.select('name').from(User).toSql(),
54
+ 'SELECT "user"."name" FROM "user"',
55
+ );
56
+ expectQueryNotMutated(q);
57
+ });
58
+
59
+ it('should add ONLY keyword when `only` parameter is provided', () => {
60
+ const q = User.all();
61
+ expectSql(
62
+ q.select('id').from(User, { only: true }).toSql(),
63
+ 'SELECT "user"."id" FROM ONLY "user"',
64
+ );
65
+ });
66
+ });
@@ -0,0 +1,58 @@
1
+ import { Query, SetQueryTableAlias } from '../query';
2
+ import { AliasOrTable, isRaw, RawExpression } from '../common';
3
+ import { SelectQueryData } from '../sql';
4
+
5
+ type FromArgs<T extends Query> = [
6
+ first:
7
+ | string
8
+ | Query
9
+ | RawExpression
10
+ | Exclude<keyof T['withData'], symbol | number>,
11
+ second?: string | { as?: string; only?: boolean },
12
+ ];
13
+
14
+ type FromResult<
15
+ T extends Query,
16
+ Args extends FromArgs<T>,
17
+ > = Args[1] extends string
18
+ ? SetQueryTableAlias<T, Args[1]>
19
+ : Args[1] extends { as: string }
20
+ ? SetQueryTableAlias<T, Args[1]['as']>
21
+ : Args[0] extends string
22
+ ? SetQueryTableAlias<T, Args[0]>
23
+ : Args[0] extends Query
24
+ ? SetQueryTableAlias<T, AliasOrTable<Args[0]>>
25
+ : T;
26
+
27
+ export class From {
28
+ from<T extends Query, Args extends FromArgs<T>>(
29
+ this: T,
30
+ ...args: Args
31
+ ): FromResult<T, Args> {
32
+ return this.clone()._from(...args) as FromResult<T, Args>;
33
+ }
34
+
35
+ _from<T extends Query, Args extends FromArgs<T>>(
36
+ this: T,
37
+ ...args: Args
38
+ ): FromResult<T, Args> {
39
+ let as: string | undefined;
40
+ if (typeof args[1] === 'string') {
41
+ as = args[1];
42
+ } else if (typeof args[1] === 'object' && args[1].as) {
43
+ as = args[1].as;
44
+ } else if (typeof args[0] === 'string') {
45
+ if (!this.query.as) as = args[0];
46
+ } else if (!isRaw(args[0] as RawExpression)) {
47
+ as = (args[0] as Query).query.as || (args[0] as Query).table;
48
+ }
49
+
50
+ if (typeof args[1] === 'object' && 'only' in args[1]) {
51
+ (this.query as SelectQueryData).fromOnly = args[1].only;
52
+ }
53
+
54
+ const q = as ? this._as(as) : this;
55
+ q.query.from = args[0];
56
+ return q as unknown as FromResult<T, Args>;
57
+ }
58
+ }
@@ -0,0 +1,66 @@
1
+ import { AssertEqual, User, userData, useTestDatabase } from '../test-utils';
2
+ import { NumberColumn } from '../columnSchema';
3
+ import { NotFoundError } from '../errors';
4
+ import { raw } from '../common';
5
+
6
+ describe('get', () => {
7
+ useTestDatabase();
8
+
9
+ describe('get', () => {
10
+ it('should select column and return a single value', async () => {
11
+ const { id } = await User.select('id').insert(userData);
12
+
13
+ const received = await User.get('id');
14
+
15
+ const eq: AssertEqual<typeof received, number> = true;
16
+ expect(eq).toBe(true);
17
+
18
+ expect(received).toBe(id);
19
+ });
20
+
21
+ it('should select raw and return a single value', async () => {
22
+ const received = await User.get(raw<NumberColumn>('count(*)::int'));
23
+
24
+ const eq: AssertEqual<typeof received, number> = true;
25
+ expect(eq).toBe(true);
26
+
27
+ expect(received).toBe(0);
28
+ });
29
+
30
+ it('should throw if not found', async () => {
31
+ await expect(() => User.get('id')).rejects.toThrowError(NotFoundError);
32
+ });
33
+ });
34
+
35
+ describe('getOptional', () => {
36
+ it('should select column and return a single value when exists', async () => {
37
+ const { id } = await User.select('id').insert(userData);
38
+
39
+ const received = await User.getOptional('id');
40
+
41
+ const eq: AssertEqual<typeof received, number | undefined> = true;
42
+ expect(eq).toBe(true);
43
+
44
+ expect(received).toBe(id);
45
+ });
46
+
47
+ it('should select raw and return a single value when exists', async () => {
48
+ const received = await User.getOptional(
49
+ raw<NumberColumn>('count(*)::int'),
50
+ );
51
+
52
+ const eq: AssertEqual<typeof received, number | undefined> = true;
53
+ expect(eq).toBe(true);
54
+
55
+ expect(received).toBe(0);
56
+ });
57
+
58
+ it('should return undefined if not found', async () => {
59
+ const value = await User.getOptional('id');
60
+ const eq: AssertEqual<typeof value, number | undefined> = true;
61
+ expect(eq).toBe(true);
62
+
63
+ expect(value).toBe(undefined);
64
+ });
65
+ });
66
+ });
@@ -0,0 +1,88 @@
1
+ import {
2
+ Query,
3
+ QueryBase,
4
+ SetQueryReturnsValue,
5
+ SetQueryReturnsValueOptional,
6
+ } from '../query';
7
+ import { RelationQueryBase } from '../relations';
8
+ import { isRaw, RawExpression } from '../common';
9
+ import { addParserForRawExpression, processSelectArg } from './select';
10
+ import { getQueryAs } from '../utils';
11
+
12
+ export type GetArg<T extends QueryBase> =
13
+ | keyof T['selectable']
14
+ | (RelationQueryBase & { returnType: 'value' | 'valueOrThrow' })
15
+ | RawExpression;
16
+
17
+ type UnwrapRaw<
18
+ T extends Query,
19
+ Arg extends GetArg<T>,
20
+ > = Arg extends RawExpression ? Arg['__column'] : Exclude<Arg, RawExpression>;
21
+
22
+ type GetResult<T extends Query, Arg extends GetArg<T>> = SetQueryReturnsValue<
23
+ T,
24
+ UnwrapRaw<T, Arg>
25
+ >;
26
+
27
+ type GetOptionalResult<
28
+ T extends Query,
29
+ Arg extends GetArg<T>,
30
+ > = SetQueryReturnsValueOptional<T, UnwrapRaw<T, Arg>>;
31
+
32
+ const _get = <
33
+ T extends Query,
34
+ R extends 'value' | 'valueOrThrow',
35
+ Arg extends GetArg<T>,
36
+ >(
37
+ q: T,
38
+ returnType: R,
39
+ arg: Arg,
40
+ ): R extends 'value' ? GetOptionalResult<T, Arg> : GetResult<T, Arg> => {
41
+ q.query.returnType = returnType;
42
+ q.query.take = true;
43
+
44
+ if (typeof arg === 'object' && isRaw(arg)) {
45
+ addParserForRawExpression(q, 'value', arg);
46
+ q.query.select = [arg];
47
+ } else {
48
+ q.query.select = [
49
+ processSelectArg(
50
+ q,
51
+ getQueryAs(q),
52
+ arg as Exclude<GetArg<T>, RawExpression>,
53
+ ),
54
+ ];
55
+ }
56
+
57
+ return q as unknown as GetResult<T, Arg> & GetOptionalResult<T, Arg>;
58
+ };
59
+
60
+ export class QueryGet {
61
+ get<T extends Query, Arg extends GetArg<T>>(
62
+ this: T,
63
+ arg: Arg,
64
+ ): GetResult<T, Arg> {
65
+ return this.clone()._get(arg);
66
+ }
67
+
68
+ _get<T extends Query, Arg extends GetArg<T>>(
69
+ this: T,
70
+ arg: Arg,
71
+ ): GetResult<T, Arg> {
72
+ return _get(this, 'valueOrThrow', arg);
73
+ }
74
+
75
+ getOptional<T extends Query, Arg extends GetArg<T>>(
76
+ this: T,
77
+ arg: Arg,
78
+ ): GetOptionalResult<T, Arg> {
79
+ return this.clone()._getOptional(arg);
80
+ }
81
+
82
+ _getOptional<T extends Query, Arg extends GetArg<T>>(
83
+ this: T,
84
+ arg: Arg,
85
+ ): GetOptionalResult<T, Arg> {
86
+ return _get(this, 'value', arg);
87
+ }
88
+ }
@@ -0,0 +1,247 @@
1
+ import { expectQueryNotMutated, expectSql, User } from '../test-utils';
2
+ import { raw } from '../common';
3
+
4
+ describe('having', () => {
5
+ it('should support { count: value } object', () => {
6
+ const q = User.all();
7
+
8
+ expectSql(
9
+ q.having({ count: 5 }).toSql(),
10
+ `
11
+ SELECT *
12
+ FROM "user"
13
+ HAVING count(*) = 5
14
+ `,
15
+ );
16
+
17
+ expectQueryNotMutated(q);
18
+ });
19
+
20
+ it('should support simple object as argument', () => {
21
+ const q = User.all();
22
+
23
+ expectSql(
24
+ q
25
+ .having({
26
+ count: {
27
+ id: 5,
28
+ },
29
+ })
30
+ .toSql(),
31
+ `
32
+ SELECT *
33
+ FROM "user"
34
+ HAVING count("user"."id") = $1
35
+ `,
36
+ [5],
37
+ );
38
+
39
+ expectQueryNotMutated(q);
40
+ });
41
+
42
+ it('should support column operators', () => {
43
+ const q = User.all();
44
+
45
+ expectSql(
46
+ q
47
+ .having({
48
+ sum: {
49
+ id: {
50
+ gt: 5,
51
+ lt: 20,
52
+ },
53
+ },
54
+ })
55
+ .toSql(),
56
+ `
57
+ SELECT *
58
+ FROM "user"
59
+ HAVING sum("user"."id") > $1 AND sum("user"."id") < $2
60
+ `,
61
+ [5, 20],
62
+ );
63
+
64
+ expectQueryNotMutated(q);
65
+ });
66
+
67
+ it('should support distinct option', () => {
68
+ const q = User.all();
69
+
70
+ expectSql(
71
+ q
72
+ .having({
73
+ count: {
74
+ id: {
75
+ equals: 10,
76
+ distinct: true,
77
+ },
78
+ },
79
+ })
80
+ .toSql(),
81
+ `
82
+ SELECT *
83
+ FROM "user"
84
+ HAVING count(DISTINCT "user"."id") = $1
85
+ `,
86
+ [10],
87
+ );
88
+
89
+ expectQueryNotMutated(q);
90
+ });
91
+
92
+ it('should support order option', () => {
93
+ const q = User.all();
94
+
95
+ expectSql(
96
+ q
97
+ .having({
98
+ count: {
99
+ id: {
100
+ equals: 10,
101
+ order: {
102
+ name: 'ASC',
103
+ },
104
+ },
105
+ },
106
+ })
107
+ .toSql(),
108
+ `
109
+ SELECT *
110
+ FROM "user"
111
+ HAVING count("user"."id" ORDER BY "user"."name" ASC) = $1
112
+ `,
113
+ [10],
114
+ );
115
+
116
+ expectQueryNotMutated(q);
117
+ });
118
+
119
+ it('should support filter and filterOr option', () => {
120
+ const q = User.all();
121
+
122
+ expectSql(
123
+ q
124
+ .having({
125
+ count: {
126
+ id: {
127
+ equals: 10,
128
+ filter: {
129
+ id: {
130
+ lt: 10,
131
+ },
132
+ },
133
+ filterOr: [
134
+ {
135
+ id: {
136
+ equals: 15,
137
+ },
138
+ },
139
+ {
140
+ id: {
141
+ gt: 20,
142
+ },
143
+ },
144
+ ],
145
+ },
146
+ },
147
+ })
148
+ .toSql(),
149
+ `
150
+ SELECT *
151
+ FROM "user"
152
+ HAVING count("user"."id")
153
+ FILTER (
154
+ WHERE "user"."id" < $1 OR "user"."id" = $2 OR "user"."id" > $3
155
+ ) = $4
156
+ `,
157
+ [10, 15, 20, 10],
158
+ );
159
+
160
+ expectQueryNotMutated(q);
161
+ });
162
+
163
+ it('should support withinGroup option', () => {
164
+ const q = User.all();
165
+
166
+ expectSql(
167
+ q
168
+ .having({
169
+ count: {
170
+ id: {
171
+ equals: 10,
172
+ withinGroup: true,
173
+ order: { name: 'ASC' },
174
+ },
175
+ },
176
+ })
177
+ .toSql(),
178
+ `
179
+ SELECT *
180
+ FROM "user"
181
+ HAVING count("user"."id") WITHIN GROUP (ORDER BY "user"."name" ASC) = $1
182
+ `,
183
+ [10],
184
+ );
185
+
186
+ expectQueryNotMutated(q);
187
+ });
188
+
189
+ it('adds having condition with raw sql', () => {
190
+ const q = User.clone();
191
+
192
+ const expectedSql = `
193
+ SELECT *
194
+ FROM "user"
195
+ HAVING count(*) = 1 AND sum(id) = 2
196
+ `;
197
+
198
+ expectSql(
199
+ q.having(raw('count(*) = 1'), raw('sum(id) = 2')).toSql(),
200
+ expectedSql,
201
+ );
202
+ expectQueryNotMutated(q);
203
+
204
+ q._having(raw('count(*) = 1'), raw('sum(id) = 2'));
205
+ expectSql(q.toSql(), expectedSql);
206
+ });
207
+
208
+ describe('havingOr', () => {
209
+ it('should join conditions with or', () => {
210
+ const q = User.all();
211
+ expectSql(
212
+ q.havingOr({ count: 1 }, { count: 2 }).toSql(),
213
+ `
214
+ SELECT * FROM "user"
215
+ HAVING count(*) = 1 OR count(*) = 2
216
+ `,
217
+ );
218
+ expectQueryNotMutated(q);
219
+ });
220
+
221
+ it('should handle sub queries', () => {
222
+ const q = User.all();
223
+ expectSql(
224
+ q
225
+ .havingOr({ count: 1 }, User.having({ count: 2 }, { count: 3 }))
226
+ .toSql(),
227
+ `
228
+ SELECT * FROM "user"
229
+ HAVING count(*) = 1 OR (count(*) = 2 AND count(*) = 3)
230
+ `,
231
+ );
232
+ expectQueryNotMutated(q);
233
+ });
234
+
235
+ it('should accept raw sql', () => {
236
+ const q = User.all();
237
+ expectSql(
238
+ q.havingOr(raw('count(*) = 1 + 2'), raw('count(*) = 2 + 3')).toSql(),
239
+ `
240
+ SELECT * FROM "user"
241
+ HAVING count(*) = 1 + 2 OR count(*) = 2 + 3
242
+ `,
243
+ );
244
+ expectQueryNotMutated(q);
245
+ });
246
+ });
247
+ });
@@ -0,0 +1,99 @@
1
+ import { Query } from '../query';
2
+ import {
3
+ AggregateItemOptions,
4
+ ColumnOperators,
5
+ HavingItem,
6
+ OrderItem,
7
+ WhereItem,
8
+ } from '../sql';
9
+ import { pushQueryArray } from '../queryDataUtils';
10
+ import { Aggregate1ArgumentTypes, AggregateOptions } from './aggregate';
11
+ import { isRaw, RawExpression } from '../common';
12
+
13
+ type HavingArgObject<
14
+ T extends Query,
15
+ Agg extends keyof Aggregate1ArgumentTypes<T>,
16
+ > = {
17
+ [Column in Exclude<Aggregate1ArgumentTypes<T>[Agg], RawExpression>]?:
18
+ | T['selectable'][Column]['column']['type']
19
+ | (ColumnOperators<T['selectable'], Column> & AggregateOptions<T>);
20
+ };
21
+
22
+ export type HavingArg<T extends Query = Query> =
23
+ | ({
24
+ [Agg in keyof Aggregate1ArgumentTypes<T>]?: HavingArgObject<T, Agg>;
25
+ } & {
26
+ count?: number | HavingArgObject<T, 'count'>;
27
+ })
28
+ | Query
29
+ | RawExpression;
30
+
31
+ const processHavingArg = <T extends Query>(arg: HavingArg<T>): HavingItem => {
32
+ if ('__model' in arg || isRaw(arg)) {
33
+ return arg;
34
+ } else {
35
+ const processed = { ...arg } as Record<
36
+ string,
37
+ Record<string, AggregateItemOptions>
38
+ >;
39
+
40
+ for (const fn in arg) {
41
+ const data = arg[fn as keyof typeof arg];
42
+ if (typeof data === 'object') {
43
+ processed[fn] = { ...data } as typeof processed[string];
44
+ for (const column in data) {
45
+ const value = data[column as keyof typeof data];
46
+
47
+ if (typeof value === 'object') {
48
+ processed[fn][column] = { ...(value as object) };
49
+
50
+ const options = value as AggregateOptions<T>;
51
+
52
+ if (
53
+ 'order' in options &&
54
+ options.order &&
55
+ !Array.isArray(options.order)
56
+ ) {
57
+ processed[fn][column].order = [options.order as OrderItem];
58
+ }
59
+
60
+ if ('filter' in options && options.filter) {
61
+ processed[fn][column].filter = options.filter as WhereItem;
62
+ }
63
+
64
+ if ('filterOr' in options && options.filterOr) {
65
+ processed[fn][column].filterOr = options.filterOr as WhereItem[];
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ return processed;
72
+ }
73
+ };
74
+
75
+ export class Having {
76
+ having<T extends Query>(this: T, ...args: HavingArg<T>[]): T {
77
+ return this.clone()._having(...args);
78
+ }
79
+
80
+ _having<T extends Query>(this: T, ...args: HavingArg<T>[]): T {
81
+ return pushQueryArray(
82
+ this,
83
+ 'having',
84
+ args.map((arg) => processHavingArg(arg)),
85
+ );
86
+ }
87
+
88
+ havingOr<T extends Query>(this: T, ...args: HavingArg<T>[]): T {
89
+ return this.clone()._havingOr(...args);
90
+ }
91
+
92
+ _havingOr<T extends Query>(this: T, ...args: HavingArg<T>[]): T {
93
+ return pushQueryArray(
94
+ this,
95
+ 'havingOr',
96
+ args.map((arg) => [processHavingArg(arg)]),
97
+ );
98
+ }
99
+ }