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,629 @@
1
+ import { raw } from '../common';
2
+ import { SelectQueryData } from '../sql';
3
+ import {
4
+ expectQueryNotMutated,
5
+ adapter,
6
+ User,
7
+ Profile,
8
+ AssertEqual,
9
+ useTestDatabase,
10
+ db,
11
+ expectSql,
12
+ userData,
13
+ now,
14
+ } from '../test-utils';
15
+ import { NumberColumn } from '../columnSchema';
16
+ import { NotFoundError } from '../errors';
17
+
18
+ describe('queryMethods', () => {
19
+ useTestDatabase();
20
+
21
+ describe('.clone', () => {
22
+ it('should return new object with the same data structures', async () => {
23
+ const cloned = User.clone();
24
+ expect(cloned).not.toBe(User);
25
+ expect(cloned.table).toBe(User.table);
26
+ expect(cloned.shape).toBe(User.shape);
27
+
28
+ const eq: AssertEqual<typeof User, typeof cloned> = true;
29
+ expect(eq).toBe(true);
30
+ });
31
+ });
32
+
33
+ describe('toSql', () => {
34
+ it('generates sql', () => {
35
+ const sql = User.toSql();
36
+ expectSql(sql, `SELECT * FROM "user"`);
37
+
38
+ const eq: AssertEqual<typeof sql, { text: string; values: unknown[] }> =
39
+ true;
40
+ expect(eq).toBe(true);
41
+ });
42
+ });
43
+
44
+ describe('.all', () => {
45
+ it('should return the same query if already all', () => {
46
+ const q = User.all();
47
+ expect(q.all()).toBe(q);
48
+ });
49
+
50
+ it('should remove `take` from query if it is set', () => {
51
+ const q = User.take();
52
+ expect((q.query as SelectQueryData)?.take).toBe(true);
53
+ expect((q.all().query as SelectQueryData)?.take).toBe(undefined);
54
+ });
55
+
56
+ it('should produce correct sql', () => {
57
+ expectSql(User.all().toSql(), `SELECT * FROM "user"`);
58
+ });
59
+ });
60
+
61
+ describe('take', () => {
62
+ it('limits to one and returns only one', async () => {
63
+ await User.insert(userData);
64
+
65
+ const q = User.all();
66
+ expectSql(q.take().toSql(), `SELECT * FROM "user" LIMIT $1`, [1]);
67
+ expectQueryNotMutated(q);
68
+
69
+ const expected = await adapter
70
+ .query('SELECT * FROM "user" LIMIT 1')
71
+ .then((res) => res.rows[0]);
72
+
73
+ const user = await q.take();
74
+ const eq: AssertEqual<typeof user, typeof User.type> = true;
75
+ expect(eq).toBe(true);
76
+
77
+ expect(user).toEqual({
78
+ ...expected,
79
+ createdAt: new Date(expected.createdAt),
80
+ updatedAt: new Date(expected.updatedAt),
81
+ });
82
+ });
83
+
84
+ it('should throw if not found', async () => {
85
+ await expect(() => User.take()).rejects.toThrowError(NotFoundError);
86
+ });
87
+ });
88
+
89
+ describe('takeOptional', () => {
90
+ it('limits to one and returns only one', async () => {
91
+ await User.insert(userData);
92
+
93
+ const q = User.all();
94
+ expectSql(q.takeOptional().toSql(), `SELECT * FROM "user" LIMIT $1`, [1]);
95
+ expectQueryNotMutated(q);
96
+
97
+ const expected = await adapter
98
+ .query('SELECT * FROM "user" LIMIT 1')
99
+ .then((res) => res.rows[0]);
100
+
101
+ const user = await q.takeOptional();
102
+ const eq: AssertEqual<typeof user, typeof User.type | undefined> = true;
103
+ expect(eq).toBe(true);
104
+
105
+ expect(user).toEqual({
106
+ ...expected,
107
+ createdAt: new Date(expected.createdAt),
108
+ updatedAt: new Date(expected.updatedAt),
109
+ });
110
+ });
111
+
112
+ it('should return undefined if not found', async () => {
113
+ const user = await User.takeOptional();
114
+ const eq: AssertEqual<typeof user, typeof User.type | undefined> = true;
115
+ expect(eq).toBe(true);
116
+
117
+ expect(user).toBe(undefined);
118
+ });
119
+ });
120
+
121
+ describe('rows', () => {
122
+ it('returns array of rows', async () => {
123
+ const { rows: expected } = await adapter.arrays({
124
+ text: 'SELECT * FROM "user"',
125
+ });
126
+ const received = await User.rows();
127
+ expect(received).toEqual(expected);
128
+ });
129
+
130
+ it('removes `take` from query data', () => {
131
+ expect((User.take().rows().query as SelectQueryData)?.take).toBe(
132
+ undefined,
133
+ );
134
+ });
135
+ });
136
+
137
+ describe('pluck', () => {
138
+ beforeEach(async () => {
139
+ for (let i = 0; i < 3; i++) {
140
+ await User.insert(userData);
141
+ }
142
+ });
143
+
144
+ it('should return array of column values, properly parsed', async () => {
145
+ const result = await User.pluck('createdAt');
146
+ expect(result).toEqual([now, now, now]);
147
+
148
+ const eq: AssertEqual<typeof result, Date[]> = true;
149
+ expect(eq).toBe(true);
150
+ });
151
+
152
+ it('should support raw expression', async () => {
153
+ const result = await User.pluck(raw<NumberColumn>('123'));
154
+ expect(result).toEqual([123, 123, 123]);
155
+
156
+ const eq: AssertEqual<typeof result, number[]> = true;
157
+ expect(eq).toBe(true);
158
+ });
159
+ });
160
+
161
+ describe('exec', () => {
162
+ it('returns nothing', async () => {
163
+ const received = await User.exec();
164
+ expect(received).toEqual(undefined);
165
+ });
166
+
167
+ it('removes `take` from query data', () => {
168
+ expect((User.take().exec().query as SelectQueryData)?.take).toBe(
169
+ undefined,
170
+ );
171
+ });
172
+ });
173
+
174
+ describe('distinct', () => {
175
+ it('should add distinct without specifying columns', () => {
176
+ const q = User.all();
177
+ expectSql(q.distinct().toSql(), 'SELECT DISTINCT * FROM "user"');
178
+ expectQueryNotMutated(q);
179
+ });
180
+
181
+ it('should add distinct on columns', () => {
182
+ const q = User.all();
183
+ expectSql(
184
+ q.distinct('id', 'name').toSql(),
185
+ `
186
+ SELECT DISTINCT ON ("user"."id", "user"."name") *
187
+ FROM "user"
188
+ `,
189
+ );
190
+ expectQueryNotMutated(q);
191
+ });
192
+
193
+ it('should add distinct on table.column', () => {
194
+ const q = User.all();
195
+ expectSql(
196
+ q.distinct('user.id', 'user.name').toSql(),
197
+ `
198
+ SELECT DISTINCT ON ("user"."id", "user"."name") *
199
+ FROM "user"
200
+ `,
201
+ );
202
+ expectQueryNotMutated(q);
203
+ });
204
+
205
+ it('should add distinct on joined columns', () => {
206
+ const q = User.all();
207
+ expectSql(
208
+ q
209
+ .join(Profile, 'profile.userId', '=', 'user.id')
210
+ .distinct('user.id', 'profile.userId')
211
+ .toSql(),
212
+ `
213
+ SELECT DISTINCT ON ("user"."id", "profile"."userId") "user".*
214
+ FROM "user"
215
+ JOIN "profile" ON "profile"."userId" = "user"."id"
216
+ `,
217
+ );
218
+ expectQueryNotMutated(q);
219
+ });
220
+
221
+ it('should add distinct on joined columns with alias', () => {
222
+ const q = User.all();
223
+ expectSql(
224
+ q
225
+ .join(Profile.as('p'), 'p.userId', '=', 'user.id')
226
+ .distinct('user.id', 'p.userId')
227
+ .toSql(),
228
+ `
229
+ SELECT DISTINCT ON ("user"."id", "p"."userId") "user".*
230
+ FROM "user"
231
+ JOIN "profile" AS "p" ON "p"."userId" = "user"."id"
232
+ `,
233
+ );
234
+ expectQueryNotMutated(q);
235
+ });
236
+
237
+ it('should add distinct on raw sql', () => {
238
+ const q = User.all();
239
+ expectSql(
240
+ q.distinct(raw('"user".id')).toSql(),
241
+ `
242
+ SELECT DISTINCT ON ("user".id) * FROM "user"
243
+ `,
244
+ );
245
+ expectQueryNotMutated(q);
246
+ });
247
+ });
248
+
249
+ describe('find', () => {
250
+ it('searches one by primary key', () => {
251
+ const q = User.all();
252
+ const query = q.find(1);
253
+
254
+ const eq: AssertEqual<Awaited<typeof query>, typeof User.type> = true;
255
+ expect(eq).toBe(true);
256
+
257
+ expectSql(
258
+ query.toSql(),
259
+ `
260
+ SELECT * FROM "user"
261
+ WHERE "user"."id" = $1
262
+ LIMIT $2
263
+ `,
264
+ [1, 1],
265
+ );
266
+ expectQueryNotMutated(q);
267
+ });
268
+
269
+ it('should accept raw sql', () => {
270
+ const q = User.all();
271
+ const query = q.find(raw('$1 + $2', 1, 2));
272
+
273
+ const eq: AssertEqual<Awaited<typeof query>, typeof User.type> = true;
274
+ expect(eq).toBe(true);
275
+
276
+ expectSql(
277
+ query.toSql(),
278
+ `
279
+ SELECT * FROM "user"
280
+ WHERE "user"."id" = $1 + $2
281
+ LIMIT $3
282
+ `,
283
+ [1, 2, 1],
284
+ );
285
+ expectQueryNotMutated(q);
286
+ });
287
+ });
288
+
289
+ describe('findOptional', () => {
290
+ it('searches one by primary key', () => {
291
+ const q = User.all();
292
+ const query = q.findOptional(1);
293
+
294
+ const eq: AssertEqual<
295
+ Awaited<typeof query>,
296
+ typeof User.type | undefined
297
+ > = true;
298
+ expect(eq).toBe(true);
299
+
300
+ expectSql(
301
+ query.toSql(),
302
+ `
303
+ SELECT * FROM "user"
304
+ WHERE "user"."id" = $1
305
+ LIMIT $2
306
+ `,
307
+ [1, 1],
308
+ );
309
+ expectQueryNotMutated(q);
310
+ });
311
+
312
+ it('should accept raw sql', () => {
313
+ const q = User.all();
314
+ const query = q.findOptional(raw('$1 + $2', 1, 2));
315
+
316
+ const eq: AssertEqual<
317
+ Awaited<typeof query>,
318
+ typeof User.type | undefined
319
+ > = true;
320
+ expect(eq).toBe(true);
321
+
322
+ expectSql(
323
+ query.toSql(),
324
+ `
325
+ SELECT * FROM "user"
326
+ WHERE "user"."id" = $1 + $2
327
+ LIMIT $3
328
+ `,
329
+ [1, 2, 1],
330
+ );
331
+ expectQueryNotMutated(q);
332
+ });
333
+ });
334
+
335
+ describe('findBy', () => {
336
+ it('like where but with take', () => {
337
+ const q = User.all();
338
+ expectSql(
339
+ q.findBy({ name: 's' }).toSql(),
340
+ `SELECT * FROM "user" WHERE "user"."name" = $1 LIMIT $2`,
341
+ ['s', 1],
342
+ );
343
+ expectQueryNotMutated(q);
344
+ });
345
+
346
+ it('should accept raw', () => {
347
+ const q = User.all();
348
+ expectSql(
349
+ q.findBy({ name: raw(`'string'`) }).toSql(),
350
+ `SELECT * FROM "user" WHERE "user"."name" = 'string' LIMIT $1`,
351
+ [1],
352
+ );
353
+ expectQueryNotMutated(q);
354
+ });
355
+ });
356
+
357
+ describe('findByOptional', () => {
358
+ it('like where but with take', () => {
359
+ const q = User.all();
360
+ const query = q.findByOptional({ name: 's' });
361
+
362
+ const eq: AssertEqual<
363
+ Awaited<typeof query>,
364
+ typeof User.type | undefined
365
+ > = true;
366
+ expect(eq).toBe(true);
367
+
368
+ expectSql(
369
+ query.toSql(),
370
+ `SELECT * FROM "user" WHERE "user"."name" = $1 LIMIT $2`,
371
+ ['s', 1],
372
+ );
373
+ expectQueryNotMutated(q);
374
+ });
375
+
376
+ it('should accept raw', () => {
377
+ const q = User.all();
378
+ const query = q.findByOptional({ name: raw(`'string'`) });
379
+
380
+ const eq: AssertEqual<
381
+ Awaited<typeof query>,
382
+ typeof User.type | undefined
383
+ > = true;
384
+ expect(eq).toBe(true);
385
+
386
+ expectSql(
387
+ query.toSql(),
388
+ `SELECT * FROM "user" WHERE "user"."name" = 'string' LIMIT $1`,
389
+ [1],
390
+ );
391
+ expectQueryNotMutated(q);
392
+ });
393
+ });
394
+
395
+ describe('as', () => {
396
+ it('sets table alias', () => {
397
+ const q = User.all();
398
+ expectSql(
399
+ q.select('id').as('as').toSql(),
400
+ 'SELECT "as"."id" FROM "user" AS "as"',
401
+ );
402
+ expectQueryNotMutated(q);
403
+ });
404
+ });
405
+
406
+ describe('withSchema', () => {
407
+ it('prefixes table with schema', () => {
408
+ const Country = db(
409
+ 'country',
410
+ (t) => ({
411
+ id: t.serial().primaryKey(),
412
+ name: t.text(),
413
+ }),
414
+ {
415
+ schema: 'geo',
416
+ },
417
+ );
418
+
419
+ const City = db('city', (t) => ({
420
+ id: t.serial().primaryKey(),
421
+ name: t.text(),
422
+ countryId: t.integer(),
423
+ }));
424
+
425
+ const q = City.all();
426
+
427
+ expectSql(
428
+ q
429
+ .join(Country, 'country.id', '=', 'city.countryId')
430
+ .select('name', { countryName: 'country.name' })
431
+ .withSchema('geo')
432
+ .toSql(),
433
+ `
434
+ SELECT "city"."name", "country"."name" AS "countryName"
435
+ FROM "geo"."city"
436
+ JOIN "geo"."country" ON "country"."id" = "city"."countryId"
437
+ `,
438
+ );
439
+
440
+ expectQueryNotMutated(q);
441
+ });
442
+ });
443
+
444
+ describe('wrap', () => {
445
+ it('should wrap query with another', () => {
446
+ const q = User.all();
447
+ expectSql(
448
+ q.select('id').wrap(User.select('id')).toSql(),
449
+ 'SELECT "t"."id" FROM (SELECT "user"."id" FROM "user") AS "t"',
450
+ );
451
+ expectQueryNotMutated(q);
452
+ });
453
+
454
+ it('should accept `as` parameter', () => {
455
+ const q = User.all();
456
+ expectSql(
457
+ q.select('id').wrap(User.select('id'), 'wrapped').toSql(),
458
+ 'SELECT "wrapped"."id" FROM (SELECT "user"."id" FROM "user") AS "wrapped"',
459
+ );
460
+ expectQueryNotMutated(q);
461
+ });
462
+ });
463
+
464
+ describe('group', () => {
465
+ it('groups by columns', () => {
466
+ const q = User.all();
467
+ expectSql(
468
+ q.group('id', 'name').toSql(),
469
+ `
470
+ SELECT * FROM "user"
471
+ GROUP BY "user"."id", "user"."name"
472
+ `,
473
+ );
474
+ expectQueryNotMutated(q);
475
+ });
476
+
477
+ it('groups by raw sql', () => {
478
+ const q = User.clone();
479
+ const expectedSql = `
480
+ SELECT * FROM "user"
481
+ GROUP BY id, name
482
+ `;
483
+ expectSql(q.group(raw('id'), raw('name')).toSql(), expectedSql);
484
+ expectQueryNotMutated(q);
485
+
486
+ q._group(raw('id'), raw('name'));
487
+ expectSql(q.toSql(), expectedSql);
488
+ });
489
+ });
490
+ });
491
+
492
+ describe('window', () => {
493
+ it('add window which can be used in `over`', () => {
494
+ const q = User.all();
495
+
496
+ expectSql(
497
+ q
498
+ .window({
499
+ w: {
500
+ partitionBy: 'id',
501
+ order: {
502
+ id: 'DESC',
503
+ },
504
+ },
505
+ })
506
+ .selectAvg('id', {
507
+ over: 'w',
508
+ })
509
+ .toSql(),
510
+ `
511
+ SELECT avg("user"."id") OVER "w" FROM "user"
512
+ WINDOW "w" AS (PARTITION BY "user"."id" ORDER BY "user"."id" DESC)
513
+ `,
514
+ );
515
+ expectQueryNotMutated(q);
516
+ });
517
+
518
+ it('adds window with raw sql', () => {
519
+ const q = User.all();
520
+
521
+ const windowSql = 'PARTITION BY id ORDER BY name DESC';
522
+ expectSql(
523
+ q
524
+ .window({ w: raw(windowSql) })
525
+ .selectAvg('id', {
526
+ over: 'w',
527
+ })
528
+ .toSql(),
529
+ `
530
+ SELECT avg("user"."id") OVER "w" FROM "user"
531
+ WINDOW "w" AS (PARTITION BY id ORDER BY name DESC)
532
+ `,
533
+ );
534
+ expectQueryNotMutated(q);
535
+ });
536
+ });
537
+
538
+ describe('order', () => {
539
+ it('should add order by column ASC when string is provided', () => {
540
+ const q = User.all();
541
+
542
+ expectSql(
543
+ q.order('id', 'name').toSql(),
544
+ `
545
+ SELECT * FROM "user"
546
+ ORDER BY "user"."id" ASC, "user"."name" ASC
547
+ `,
548
+ );
549
+
550
+ expectQueryNotMutated(q);
551
+ });
552
+
553
+ it('should handle object parameter', () => {
554
+ const q = User.all();
555
+ expectSql(
556
+ q.order({ id: 'ASC', name: 'DESC' }).toSql(),
557
+ `
558
+ SELECT * FROM "user"
559
+ ORDER BY "user"."id" ASC, "user"."name" DESC
560
+ `,
561
+ );
562
+ expectSql(
563
+ q
564
+ .order({
565
+ id: { dir: 'ASC', nulls: 'FIRST' },
566
+ name: { dir: 'DESC', nulls: 'LAST' },
567
+ })
568
+ .toSql(),
569
+ `
570
+ SELECT * FROM "user"
571
+ ORDER BY "user"."id" ASC NULLS FIRST, "user"."name" DESC NULLS LAST
572
+ `,
573
+ );
574
+ expectQueryNotMutated(q);
575
+ });
576
+
577
+ it('adds order with raw sql', () => {
578
+ const q = User.all();
579
+ expectSql(
580
+ q.order(raw('id ASC NULLS FIRST')).toSql(),
581
+ `
582
+ SELECT * FROM "user"
583
+ ORDER BY id ASC NULLS FIRST
584
+ `,
585
+ );
586
+ expectQueryNotMutated(q);
587
+ });
588
+ });
589
+
590
+ describe('limit', () => {
591
+ it('sets limit', () => {
592
+ const q = User.all();
593
+ expectSql(q.limit(5).toSql(), 'SELECT * FROM "user" LIMIT $1', [5]);
594
+ expectQueryNotMutated(q);
595
+ });
596
+ });
597
+
598
+ describe('offset', () => {
599
+ it('sets offset', () => {
600
+ const q = User.all();
601
+ expectSql(q.offset(5).toSql(), 'SELECT * FROM "user" OFFSET $1', [5]);
602
+ expectQueryNotMutated(q);
603
+ });
604
+ });
605
+
606
+ describe('exists', () => {
607
+ it('selects 1', () => {
608
+ const q = User.all();
609
+ expectSql(q.exists().toSql(), 'SELECT 1 FROM "user"');
610
+ expectQueryNotMutated(q);
611
+ });
612
+ });
613
+
614
+ describe('truncate', () => {
615
+ it('should truncate table', () => {
616
+ const q = User.all();
617
+ expectSql(q.truncate().toSql(), 'TRUNCATE "user"');
618
+ expectQueryNotMutated(q);
619
+ });
620
+
621
+ it('should handle restart identity and cascade options', () => {
622
+ const q = User.all();
623
+ expectSql(
624
+ q.truncate({ restartIdentity: true, cascade: true }).toSql(),
625
+ 'TRUNCATE "user" RESTART IDENTITY CASCADE',
626
+ );
627
+ expectQueryNotMutated(q);
628
+ });
629
+ });