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,89 @@
1
+ import { Query } from '../query';
2
+ import { pushQueryArray } from '../queryDataUtils';
3
+ import { RawExpression } from '../common';
4
+
5
+ export type UnionArg<T extends Query> =
6
+ | (Omit<Query, 'result'> & { result: T['result'] })
7
+ | RawExpression;
8
+
9
+ export class Union {
10
+ union<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
11
+ return this._union(args, wrap);
12
+ }
13
+
14
+ _union<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
15
+ return pushQueryArray(
16
+ this,
17
+ 'union',
18
+ args.map((arg) => ({ arg, kind: 'UNION' as const, wrap })),
19
+ );
20
+ }
21
+
22
+ unionAll<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
23
+ return this._unionAll(args, wrap);
24
+ }
25
+
26
+ _unionAll<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
27
+ return pushQueryArray(
28
+ this,
29
+ 'union',
30
+ args.map((arg) => ({ arg, kind: 'UNION ALL' as const, wrap })),
31
+ );
32
+ }
33
+
34
+ intersect<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
35
+ return this._intersect(args, wrap);
36
+ }
37
+
38
+ _intersect<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
39
+ return pushQueryArray(
40
+ this,
41
+ 'union',
42
+ args.map((arg) => ({ arg, kind: 'INTERSECT' as const, wrap })),
43
+ );
44
+ }
45
+
46
+ intersectAll<T extends Query>(
47
+ this: T,
48
+ args: UnionArg<T>[],
49
+ wrap?: boolean,
50
+ ): T {
51
+ return this._intersectAll(args, wrap);
52
+ }
53
+
54
+ _intersectAll<T extends Query>(
55
+ this: T,
56
+ args: UnionArg<T>[],
57
+ wrap?: boolean,
58
+ ): T {
59
+ return pushQueryArray(
60
+ this,
61
+ 'union',
62
+ args.map((arg) => ({ arg, kind: 'INTERSECT ALL' as const, wrap })),
63
+ );
64
+ }
65
+
66
+ except<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
67
+ return this._except(args, wrap);
68
+ }
69
+
70
+ _except<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
71
+ return pushQueryArray(
72
+ this,
73
+ 'union',
74
+ args.map((arg) => ({ arg, kind: 'EXCEPT' as const, wrap })),
75
+ );
76
+ }
77
+
78
+ exceptAll<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
79
+ return this._exceptAll(args, wrap);
80
+ }
81
+
82
+ _exceptAll<T extends Query>(this: T, args: UnionArg<T>[], wrap?: boolean): T {
83
+ return pushQueryArray(
84
+ this,
85
+ 'union',
86
+ args.map((arg) => ({ arg, kind: 'EXCEPT ALL' as const, wrap })),
87
+ );
88
+ }
89
+ }
@@ -0,0 +1,417 @@
1
+ import {
2
+ AssertEqual,
3
+ expectMatchObjectWithTimestamps,
4
+ expectQueryNotMutated,
5
+ expectSql,
6
+ User,
7
+ userData,
8
+ useTestDatabase,
9
+ } from '../test-utils';
10
+ import { raw } from '../common';
11
+
12
+ describe('update', () => {
13
+ useTestDatabase();
14
+
15
+ const update = {
16
+ name: 'new name',
17
+ password: 'new password',
18
+ };
19
+
20
+ it('should not mutate query', () => {
21
+ const q = User.all();
22
+ q.where({ name: 'name' }).update(update);
23
+ expectQueryNotMutated(q);
24
+ });
25
+
26
+ it('should throw when updating without where condition', () => {
27
+ // @ts-expect-error update should have where condition or forceAll flag
28
+ expect(() => User.update({ name: 'new name' })).toThrow();
29
+ });
30
+
31
+ it('should run without where condition when forceAll flag provided', async () => {
32
+ await expect(
33
+ User.update({ name: 'new name' }, true),
34
+ ).resolves.not.toThrow();
35
+ });
36
+
37
+ it('should update record with raw sql, returning updated rows count', async () => {
38
+ const count = 2;
39
+ const users = await User.select('id').insert([userData, userData]);
40
+
41
+ const query = User.or(...users).update(raw(`name = 'name'`));
42
+ expectSql(
43
+ query.toSql(),
44
+ `
45
+ UPDATE "user"
46
+ SET name = 'name'
47
+ WHERE "user"."id" = $1 OR "user"."id" = $2
48
+ `,
49
+ [users[0].id, users[1].id],
50
+ );
51
+
52
+ const eq: AssertEqual<Awaited<typeof query>, number> = true;
53
+ expect(eq).toBe(true);
54
+
55
+ const result = await query;
56
+ expect(result).toBe(count);
57
+ });
58
+
59
+ it('should update record, returning updated row count', async () => {
60
+ const { id } = await User.select('id').insert(userData);
61
+
62
+ const update = {
63
+ name: 'new name',
64
+ password: 'new password',
65
+ };
66
+
67
+ const query = User.where({ id }).update(update);
68
+ expectSql(
69
+ query.toSql(),
70
+ `
71
+ UPDATE "user"
72
+ SET "name" = $1,
73
+ "password" = $2
74
+ WHERE "user"."id" = $3
75
+ `,
76
+ [update.name, update.password, id],
77
+ );
78
+
79
+ const result = await query;
80
+ const eq: AssertEqual<typeof result, number> = true;
81
+ expect(eq).toBe(true);
82
+
83
+ expect(result).toBe(1);
84
+
85
+ const updated = await User.take();
86
+ expectMatchObjectWithTimestamps(updated, { ...userData, ...update });
87
+ });
88
+
89
+ it('should update record, returning value', async () => {
90
+ const id = await User.get('id').insert(userData);
91
+
92
+ const update = {
93
+ name: 'new name',
94
+ password: 'new password',
95
+ };
96
+
97
+ const query = User.find(id).get('id').update(update);
98
+ expectSql(
99
+ query.toSql(),
100
+ `
101
+ UPDATE "user"
102
+ SET "name" = $1,
103
+ "password" = $2
104
+ WHERE "user"."id" = $3
105
+ RETURNING "user"."id"
106
+ `,
107
+ [update.name, update.password, id],
108
+ );
109
+
110
+ const result = await query;
111
+ const eq: AssertEqual<typeof result, number> = true;
112
+ expect(eq).toBe(true);
113
+
114
+ expect(typeof result).toBe('number');
115
+
116
+ const updated = await User.take();
117
+ expectMatchObjectWithTimestamps(updated, { ...userData, ...update });
118
+ });
119
+
120
+ it('should update one record, return selected columns', async () => {
121
+ const id = await User.get('id').insert(userData);
122
+
123
+ const query = User.select('id', 'name').find(id).update(update);
124
+
125
+ expectSql(
126
+ query.toSql(),
127
+ `
128
+ UPDATE "user"
129
+ SET "name" = $1,
130
+ "password" = $2
131
+ WHERE "user"."id" = $3
132
+ RETURNING "user"."id", "user"."name"
133
+ `,
134
+ [update.name, update.password, id],
135
+ );
136
+
137
+ const result = await query;
138
+ const eq: AssertEqual<typeof result, { id: number; name: string }> = true;
139
+ expect(eq).toBe(true);
140
+
141
+ const updated = await User.take();
142
+ expectMatchObjectWithTimestamps(updated, { ...userData, ...update });
143
+ });
144
+
145
+ it('should update one record, return all columns', async () => {
146
+ const id = await User.get('id').insert(userData);
147
+
148
+ const query = User.selectAll().find(id).update(update);
149
+
150
+ expectSql(
151
+ query.toSql(),
152
+ `
153
+ UPDATE "user"
154
+ SET "name" = $1,
155
+ "password" = $2
156
+ WHERE "user"."id" = $3
157
+ RETURNING *
158
+ `,
159
+ [update.name, update.password, id],
160
+ );
161
+
162
+ const result = await query;
163
+ const eq: AssertEqual<typeof result, typeof User.type> = true;
164
+ expect(eq).toBe(true);
165
+
166
+ const updated = await User.take();
167
+ expectMatchObjectWithTimestamps(updated, { ...userData, ...update });
168
+ });
169
+
170
+ it('should update multiple records, returning selected columns', async () => {
171
+ const ids = await User.pluck('id').insert([userData, userData]);
172
+
173
+ const update = {
174
+ name: 'new name',
175
+ password: 'new password',
176
+ };
177
+
178
+ const query = User.select('id', 'name')
179
+ .where({ id: { in: ids } })
180
+ .update(update);
181
+
182
+ expectSql(
183
+ query.toSql(),
184
+ `
185
+ UPDATE "user"
186
+ SET "name" = $1,
187
+ "password" = $2
188
+ WHERE "user"."id" IN ($3, $4)
189
+ RETURNING "user"."id", "user"."name"
190
+ `,
191
+ [update.name, update.password, ids[0], ids[1]],
192
+ );
193
+
194
+ const result = await query;
195
+ const eq: AssertEqual<typeof result, { id: number; name: string }[]> = true;
196
+ expect(eq).toBe(true);
197
+
198
+ const updated = await User.take();
199
+ expectMatchObjectWithTimestamps(updated, { ...userData, ...update });
200
+ });
201
+
202
+ it('should update multiple records, returning all columns', async () => {
203
+ const ids = await User.pluck('id').insert([userData, userData]);
204
+
205
+ const update = {
206
+ name: 'new name',
207
+ password: 'new password',
208
+ };
209
+
210
+ const query = User.selectAll()
211
+ .where({ id: { in: ids } })
212
+ .update(update);
213
+
214
+ expectSql(
215
+ query.toSql(),
216
+ `
217
+ UPDATE "user"
218
+ SET "name" = $1,
219
+ "password" = $2
220
+ WHERE "user"."id" IN ($3, $4)
221
+ RETURNING *
222
+ `,
223
+ [update.name, update.password, ids[0], ids[1]],
224
+ );
225
+
226
+ const result = await query;
227
+ expectMatchObjectWithTimestamps(result[0], { ...userData, ...update });
228
+
229
+ const eq: AssertEqual<typeof result, typeof User['type'][]> = true;
230
+ expect(eq).toBe(true);
231
+
232
+ const updated = await User.take();
233
+ expectMatchObjectWithTimestamps(updated, { ...userData, ...update });
234
+ });
235
+
236
+ it('should ignore undefined values, and should not ignore null', () => {
237
+ const query = User.where({ id: 1 }).update({
238
+ name: 'new name',
239
+ password: undefined,
240
+ data: null,
241
+ });
242
+ expectSql(
243
+ query.toSql(),
244
+ `
245
+ UPDATE "user"
246
+ SET "name" = $1,
247
+ "data" = $2
248
+ WHERE "user"."id" = $3
249
+ `,
250
+ ['new name', null, 1],
251
+ );
252
+
253
+ const eq: AssertEqual<Awaited<typeof query>, number> = true;
254
+ expect(eq).toBe(true);
255
+ });
256
+
257
+ it('should support raw sql as a value', () => {
258
+ const query = User.where({ id: 1 }).update({
259
+ name: raw(`'raw sql'`),
260
+ });
261
+ expectSql(
262
+ query.toSql(),
263
+ `
264
+ UPDATE "user"
265
+ SET "name" = 'raw sql'
266
+ WHERE "user"."id" = $1
267
+ `,
268
+ [1],
269
+ );
270
+
271
+ const eq: AssertEqual<Awaited<typeof query>, number> = true;
272
+ expect(eq).toBe(true);
273
+ });
274
+
275
+ it('should return one record when searching for one to update', async () => {
276
+ const { id } = await User.select('id').insert(userData);
277
+
278
+ const update = {
279
+ name: 'new name',
280
+ password: 'new password',
281
+ };
282
+
283
+ const query = User.selectAll().findBy({ id }).update(update);
284
+ expectSql(
285
+ query.toSql(),
286
+ `
287
+ UPDATE "user"
288
+ SET "name" = $1,
289
+ "password" = $2
290
+ WHERE "user"."id" = $3
291
+ RETURNING *
292
+ `,
293
+ [update.name, update.password, id],
294
+ );
295
+
296
+ const result = await query;
297
+ const eq: AssertEqual<typeof result, typeof User.type> = true;
298
+ expect(eq).toBe(true);
299
+
300
+ expectMatchObjectWithTimestamps(result, { ...userData, ...update });
301
+ });
302
+
303
+ it('should throw when searching for one to update and it is not found', async () => {
304
+ const query = User.selectAll()
305
+ .findBy({ id: 1 })
306
+ .update({ name: 'new name' });
307
+
308
+ const eq: AssertEqual<Awaited<typeof query>, typeof User.type> = true;
309
+ expect(eq).toBe(true);
310
+
311
+ await expect(query).rejects.toThrow();
312
+ });
313
+
314
+ describe('updateOrThrow', () => {
315
+ it('should throw if no records were found for update', async () => {
316
+ await expect(
317
+ User.where({ name: 'not found' }).updateOrThrow({ name: 'name' }),
318
+ ).rejects.toThrow();
319
+
320
+ await expect(
321
+ User.select('id')
322
+ .where({ name: 'not found' })
323
+ .updateOrThrow({ name: 'name' }),
324
+ ).rejects.toThrow();
325
+ });
326
+ });
327
+
328
+ describe('increment', () => {
329
+ it('should not mutate query', () => {
330
+ const q = User.all();
331
+ q.where({ name: 'name' }).increment('age');
332
+ expectQueryNotMutated(q);
333
+ });
334
+
335
+ it('should increment column by 1', () => {
336
+ const query = User.increment('age');
337
+ expectSql(
338
+ query.toSql(),
339
+ `
340
+ UPDATE "user"
341
+ SET "age" = "age" + $1
342
+ `,
343
+ [1],
344
+ );
345
+ });
346
+
347
+ it('should increment column by provided amount', () => {
348
+ const query = User.increment({ age: 3 });
349
+ expectSql(
350
+ query.toSql(),
351
+ `
352
+ UPDATE "user"
353
+ SET "age" = "age" + $1
354
+ `,
355
+ [3],
356
+ );
357
+ });
358
+
359
+ it('should support returning', () => {
360
+ const query = User.select('id').increment({ age: 3 });
361
+ expectSql(
362
+ query.toSql(),
363
+ `
364
+ UPDATE "user"
365
+ SET "age" = "age" + $1
366
+ RETURNING "user"."id"
367
+ `,
368
+ [3],
369
+ );
370
+
371
+ const eq: AssertEqual<Awaited<typeof query>, { id: number }[]> = true;
372
+ expect(eq).toBe(true);
373
+ });
374
+ });
375
+
376
+ describe('decrement', () => {
377
+ it('should decrement column by 1', () => {
378
+ const query = User.decrement('age');
379
+ expectSql(
380
+ query.toSql(),
381
+ `
382
+ UPDATE "user"
383
+ SET "age" = "age" - $1
384
+ `,
385
+ [1],
386
+ );
387
+ });
388
+
389
+ it('should decrement column by provided amount', () => {
390
+ const query = User.decrement({ age: 3 });
391
+ expectSql(
392
+ query.toSql(),
393
+ `
394
+ UPDATE "user"
395
+ SET "age" = "age" - $1
396
+ `,
397
+ [3],
398
+ );
399
+ });
400
+
401
+ it('should support returning', () => {
402
+ const query = User.select('id').decrement({ age: 3 });
403
+ expectSql(
404
+ query.toSql(),
405
+ `
406
+ UPDATE "user"
407
+ SET "age" = "age" - $1
408
+ RETURNING "user"."id"
409
+ `,
410
+ [3],
411
+ );
412
+
413
+ const eq: AssertEqual<Awaited<typeof query>, { id: number }[]> = true;
414
+ expect(eq).toBe(true);
415
+ });
416
+ });
417
+ });