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.
- package/dist/index.d.ts +3630 -0
- package/dist/index.esm.js +4587 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +4691 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
- package/rollup.config.js +35 -0
- package/src/adapter.test.ts +10 -0
- package/src/adapter.ts +171 -0
- package/src/columnSchema/array.ts +21 -0
- package/src/columnSchema/boolean.ts +10 -0
- package/src/columnSchema/columnType.test.ts +129 -0
- package/src/columnSchema/columnType.ts +77 -0
- package/src/columnSchema/columnTypes.ts +145 -0
- package/src/columnSchema/columnsSchema.test.ts +32 -0
- package/src/columnSchema/columnsSchema.ts +100 -0
- package/src/columnSchema/commonMethods.ts +130 -0
- package/src/columnSchema/dateTime.ts +104 -0
- package/src/columnSchema/enum.ts +13 -0
- package/src/columnSchema/index.ts +11 -0
- package/src/columnSchema/json/array.ts +55 -0
- package/src/columnSchema/json/discriminatedUnion.ts +91 -0
- package/src/columnSchema/json/enum.ts +29 -0
- package/src/columnSchema/json/instanceOf.ts +16 -0
- package/src/columnSchema/json/intersection.ts +23 -0
- package/src/columnSchema/json/lazy.ts +22 -0
- package/src/columnSchema/json/literal.ts +12 -0
- package/src/columnSchema/json/map.ts +29 -0
- package/src/columnSchema/json/nativeEnum.ts +30 -0
- package/src/columnSchema/json/nullable.ts +33 -0
- package/src/columnSchema/json/nullish.ts +30 -0
- package/src/columnSchema/json/object.ts +206 -0
- package/src/columnSchema/json/optional.ts +28 -0
- package/src/columnSchema/json/record.ts +40 -0
- package/src/columnSchema/json/scalarTypes.ts +117 -0
- package/src/columnSchema/json/set.ts +34 -0
- package/src/columnSchema/json/tuple.ts +40 -0
- package/src/columnSchema/json/typeBase.ts +202 -0
- package/src/columnSchema/json/union.ts +16 -0
- package/src/columnSchema/json.ts +64 -0
- package/src/columnSchema/number.ts +122 -0
- package/src/columnSchema/string.ts +222 -0
- package/src/columnSchema/utils.ts +27 -0
- package/src/common.ts +86 -0
- package/src/db.test.ts +67 -0
- package/src/db.ts +212 -0
- package/src/errors.ts +7 -0
- package/src/index.ts +18 -0
- package/src/operators.test.ts +608 -0
- package/src/operators.ts +177 -0
- package/src/query.ts +292 -0
- package/src/queryDataUtils.ts +50 -0
- package/src/queryMethods/aggregate.test.ts +583 -0
- package/src/queryMethods/aggregate.ts +878 -0
- package/src/queryMethods/callbacks.test.ts +69 -0
- package/src/queryMethods/callbacks.ts +55 -0
- package/src/queryMethods/clear.test.ts +64 -0
- package/src/queryMethods/clear.ts +58 -0
- package/src/queryMethods/columnInfo.test.ts +45 -0
- package/src/queryMethods/columnInfo.ts +67 -0
- package/src/queryMethods/delete.test.ts +135 -0
- package/src/queryMethods/delete.ts +50 -0
- package/src/queryMethods/for.test.ts +57 -0
- package/src/queryMethods/for.ts +99 -0
- package/src/queryMethods/from.test.ts +66 -0
- package/src/queryMethods/from.ts +58 -0
- package/src/queryMethods/get.test.ts +66 -0
- package/src/queryMethods/get.ts +88 -0
- package/src/queryMethods/having.test.ts +247 -0
- package/src/queryMethods/having.ts +99 -0
- package/src/queryMethods/insert.test.ts +555 -0
- package/src/queryMethods/insert.ts +453 -0
- package/src/queryMethods/join.test.ts +150 -0
- package/src/queryMethods/join.ts +508 -0
- package/src/queryMethods/json.test.ts +398 -0
- package/src/queryMethods/json.ts +259 -0
- package/src/queryMethods/log.test.ts +172 -0
- package/src/queryMethods/log.ts +123 -0
- package/src/queryMethods/queryMethods.test.ts +629 -0
- package/src/queryMethods/queryMethods.ts +428 -0
- package/src/queryMethods/select.test.ts +479 -0
- package/src/queryMethods/select.ts +249 -0
- package/src/queryMethods/then.ts +236 -0
- package/src/queryMethods/transaction.test.ts +66 -0
- package/src/queryMethods/transaction.ts +66 -0
- package/src/queryMethods/union.test.ts +59 -0
- package/src/queryMethods/union.ts +89 -0
- package/src/queryMethods/update.test.ts +417 -0
- package/src/queryMethods/update.ts +350 -0
- package/src/queryMethods/upsert.test.ts +56 -0
- package/src/queryMethods/upsert.ts +43 -0
- package/src/queryMethods/where.test.ts +1594 -0
- package/src/queryMethods/where.ts +450 -0
- package/src/queryMethods/window.test.ts +66 -0
- package/src/queryMethods/window.ts +108 -0
- package/src/queryMethods/with.test.ts +191 -0
- package/src/queryMethods/with.ts +92 -0
- package/src/quote.ts +36 -0
- package/src/relations.ts +194 -0
- package/src/sql/aggregate.ts +80 -0
- package/src/sql/columnInfo.ts +22 -0
- package/src/sql/common.ts +42 -0
- package/src/sql/delete.ts +41 -0
- package/src/sql/distinct.ts +19 -0
- package/src/sql/fromAndAs.ts +51 -0
- package/src/sql/having.ts +140 -0
- package/src/sql/index.ts +2 -0
- package/src/sql/insert.ts +102 -0
- package/src/sql/join.ts +242 -0
- package/src/sql/orderBy.ts +41 -0
- package/src/sql/select.ts +153 -0
- package/src/sql/toSql.ts +153 -0
- package/src/sql/truncate.ts +13 -0
- package/src/sql/types.ts +355 -0
- package/src/sql/update.ts +62 -0
- package/src/sql/where.ts +314 -0
- package/src/sql/window.ts +38 -0
- package/src/sql/with.ts +32 -0
- package/src/test-utils.ts +172 -0
- package/src/utils.ts +140 -0
- package/tsconfig.build.json +6 -0
- 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
|
+
});
|