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,398 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AssertEqual,
|
|
3
|
+
expectQueryNotMutated,
|
|
4
|
+
expectSql,
|
|
5
|
+
User,
|
|
6
|
+
userData,
|
|
7
|
+
useTestDatabase,
|
|
8
|
+
} from '../test-utils';
|
|
9
|
+
import { columnTypes } from '../columnSchema';
|
|
10
|
+
|
|
11
|
+
describe('json methods', () => {
|
|
12
|
+
useTestDatabase();
|
|
13
|
+
|
|
14
|
+
describe('json', () => {
|
|
15
|
+
it('wraps a query with json functions', () => {
|
|
16
|
+
const q = User.all();
|
|
17
|
+
expectSql(
|
|
18
|
+
q.where({ id: 1 }).json().toSql(),
|
|
19
|
+
`
|
|
20
|
+
SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
|
|
21
|
+
FROM (
|
|
22
|
+
SELECT * FROM "user"
|
|
23
|
+
WHERE "user"."id" = $1
|
|
24
|
+
) AS "t"
|
|
25
|
+
`,
|
|
26
|
+
[1],
|
|
27
|
+
);
|
|
28
|
+
expectQueryNotMutated(q);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('supports `take`', () => {
|
|
32
|
+
const q = User.all();
|
|
33
|
+
expectSql(
|
|
34
|
+
q.where({ id: 1 }).take().json().toSql(),
|
|
35
|
+
`
|
|
36
|
+
SELECT row_to_json("t".*)
|
|
37
|
+
FROM (
|
|
38
|
+
SELECT * FROM "user"
|
|
39
|
+
WHERE "user"."id" = $1
|
|
40
|
+
LIMIT $2
|
|
41
|
+
) AS "t"
|
|
42
|
+
`,
|
|
43
|
+
[1, 1],
|
|
44
|
+
);
|
|
45
|
+
expectQueryNotMutated(q);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('processing and selecting json data', () => {
|
|
50
|
+
beforeEach(async () => {
|
|
51
|
+
await User.insert({
|
|
52
|
+
...userData,
|
|
53
|
+
data: { name: 'value', tags: ['one'] },
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('jsonSet', () => {
|
|
58
|
+
it('should select json with updated property', async () => {
|
|
59
|
+
const q = User.all();
|
|
60
|
+
|
|
61
|
+
const query = q.jsonSet('data', ['name'], 'new value');
|
|
62
|
+
expectSql(
|
|
63
|
+
query.toSql(),
|
|
64
|
+
`
|
|
65
|
+
SELECT jsonb_set("user"."data", '{name}', $1) AS "data"
|
|
66
|
+
FROM "user"
|
|
67
|
+
`,
|
|
68
|
+
['"new value"'],
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const result = await query.take();
|
|
72
|
+
expect(result.data).toEqual({ name: 'new value', tags: ['one'] });
|
|
73
|
+
|
|
74
|
+
const eq: AssertEqual<
|
|
75
|
+
typeof result.data,
|
|
76
|
+
{ name: string; tags: string[] } | null
|
|
77
|
+
> = true;
|
|
78
|
+
expect(eq).toBe(true);
|
|
79
|
+
|
|
80
|
+
expectQueryNotMutated(q);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should accept optional `as`, `createIfMissing`', async () => {
|
|
84
|
+
const q = User.all();
|
|
85
|
+
|
|
86
|
+
const query = q.jsonSet('data', ['name'], 'new value', {
|
|
87
|
+
as: 'alias',
|
|
88
|
+
createIfMissing: true,
|
|
89
|
+
});
|
|
90
|
+
expectSql(
|
|
91
|
+
query.toSql(),
|
|
92
|
+
`
|
|
93
|
+
SELECT jsonb_set("user"."data", '{name}', $1, true) AS "alias"
|
|
94
|
+
FROM "user"
|
|
95
|
+
`,
|
|
96
|
+
['"new value"'],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const result = await query.take();
|
|
100
|
+
expect(result.alias).toEqual({ name: 'new value', tags: ['one'] });
|
|
101
|
+
|
|
102
|
+
const eq: AssertEqual<
|
|
103
|
+
typeof result.alias,
|
|
104
|
+
{ name: string; tags: string[] } | null
|
|
105
|
+
> = true;
|
|
106
|
+
expect(eq).toBe(true);
|
|
107
|
+
|
|
108
|
+
expectQueryNotMutated(q);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('supports nesting', async () => {
|
|
112
|
+
const q = User.all();
|
|
113
|
+
|
|
114
|
+
const query = q.jsonSet(
|
|
115
|
+
q.jsonInsert('data', ['tags', 0], 'two'),
|
|
116
|
+
['name'],
|
|
117
|
+
'new value',
|
|
118
|
+
);
|
|
119
|
+
expectSql(
|
|
120
|
+
query.toSql(),
|
|
121
|
+
`
|
|
122
|
+
SELECT jsonb_set(
|
|
123
|
+
jsonb_insert("user"."data", '{tags, 0}', $1),
|
|
124
|
+
'{name}', $2
|
|
125
|
+
) AS "data"
|
|
126
|
+
FROM "user"
|
|
127
|
+
`,
|
|
128
|
+
['"two"', '"new value"'],
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const result = await query.take();
|
|
132
|
+
expect(result.data).toEqual({
|
|
133
|
+
name: 'new value',
|
|
134
|
+
tags: ['two', 'one'],
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const eq: AssertEqual<
|
|
138
|
+
typeof result.data,
|
|
139
|
+
{ name: string; tags: string[] } | null
|
|
140
|
+
> = true;
|
|
141
|
+
expect(eq).toBe(true);
|
|
142
|
+
|
|
143
|
+
expectQueryNotMutated(q);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('jsonInsert', () => {
|
|
148
|
+
it('should select json with updated property', async () => {
|
|
149
|
+
const q = User.all();
|
|
150
|
+
|
|
151
|
+
const query = q.jsonInsert('data', ['tags', 0], 'two');
|
|
152
|
+
expectSql(
|
|
153
|
+
query.toSql(),
|
|
154
|
+
`
|
|
155
|
+
SELECT jsonb_insert("user"."data", '{tags, 0}', $1) AS "data"
|
|
156
|
+
FROM "user"
|
|
157
|
+
`,
|
|
158
|
+
['"two"'],
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const result = await query.take();
|
|
162
|
+
expect(result.data).toEqual({ name: 'value', tags: ['two', 'one'] });
|
|
163
|
+
|
|
164
|
+
const eq: AssertEqual<
|
|
165
|
+
typeof result.data,
|
|
166
|
+
{ name: string; tags: string[] } | null
|
|
167
|
+
> = true;
|
|
168
|
+
expect(eq).toBe(true);
|
|
169
|
+
|
|
170
|
+
expectQueryNotMutated(q);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should accept optional `as`, `insertAfter`', async () => {
|
|
174
|
+
const q = User.all();
|
|
175
|
+
|
|
176
|
+
const query = q.jsonInsert('data', ['tags', 0], 'two', {
|
|
177
|
+
as: 'alias',
|
|
178
|
+
insertAfter: true,
|
|
179
|
+
});
|
|
180
|
+
expectSql(
|
|
181
|
+
query.toSql(),
|
|
182
|
+
`
|
|
183
|
+
SELECT jsonb_insert("user"."data", '{tags, 0}', $1, true) AS "alias"
|
|
184
|
+
FROM "user"
|
|
185
|
+
`,
|
|
186
|
+
['"two"'],
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const result = await query.take();
|
|
190
|
+
expect(result.alias).toEqual({ name: 'value', tags: ['one', 'two'] });
|
|
191
|
+
|
|
192
|
+
const eq: AssertEqual<
|
|
193
|
+
typeof result.alias,
|
|
194
|
+
{ name: string; tags: string[] } | null
|
|
195
|
+
> = true;
|
|
196
|
+
expect(eq).toBe(true);
|
|
197
|
+
|
|
198
|
+
expectQueryNotMutated(q);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('supports nesting', async () => {
|
|
202
|
+
const q = User.all();
|
|
203
|
+
|
|
204
|
+
const query = q.jsonInsert(
|
|
205
|
+
q.jsonSet('data', ['tags'], []),
|
|
206
|
+
['tags', 0],
|
|
207
|
+
'tag',
|
|
208
|
+
);
|
|
209
|
+
expectSql(
|
|
210
|
+
query.toSql(),
|
|
211
|
+
`
|
|
212
|
+
SELECT jsonb_insert(
|
|
213
|
+
jsonb_set("user"."data", '{tags}', $1),
|
|
214
|
+
'{tags, 0}', $2
|
|
215
|
+
) AS "data"
|
|
216
|
+
FROM "user"
|
|
217
|
+
`,
|
|
218
|
+
['[]', '"tag"'],
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const result = await query.take();
|
|
222
|
+
expect(result.data).toEqual({ name: 'value', tags: ['tag'] });
|
|
223
|
+
|
|
224
|
+
const eq: AssertEqual<
|
|
225
|
+
typeof result.data,
|
|
226
|
+
{ name: string; tags: string[] } | null
|
|
227
|
+
> = true;
|
|
228
|
+
expect(eq).toBe(true);
|
|
229
|
+
|
|
230
|
+
expectQueryNotMutated(q);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe('jsonRemove', () => {
|
|
235
|
+
it('should select json with removed property', async () => {
|
|
236
|
+
const q = User.all();
|
|
237
|
+
|
|
238
|
+
const query = q.jsonRemove('data', ['tags', 0]);
|
|
239
|
+
expectSql(
|
|
240
|
+
query.toSql(),
|
|
241
|
+
`
|
|
242
|
+
SELECT "user"."data" #- '{tags, 0}' AS "data"
|
|
243
|
+
FROM "user"
|
|
244
|
+
`,
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const result = await query.take();
|
|
248
|
+
expect(result.data).toEqual({ name: 'value', tags: [] });
|
|
249
|
+
|
|
250
|
+
const eq: AssertEqual<
|
|
251
|
+
typeof result.data,
|
|
252
|
+
{ name: string; tags: string[] } | null
|
|
253
|
+
> = true;
|
|
254
|
+
expect(eq).toBe(true);
|
|
255
|
+
|
|
256
|
+
expectQueryNotMutated(q);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should accept optional `as`', async () => {
|
|
260
|
+
const q = User.all();
|
|
261
|
+
|
|
262
|
+
const query = q.jsonRemove('data', ['tags', 0], { as: 'alias' });
|
|
263
|
+
expectSql(
|
|
264
|
+
query.toSql(),
|
|
265
|
+
`
|
|
266
|
+
SELECT "user"."data" #- '{tags, 0}' AS "alias"
|
|
267
|
+
FROM "user"
|
|
268
|
+
`,
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const result = await query.take();
|
|
272
|
+
expect(result.alias).toEqual({ name: 'value', tags: [] });
|
|
273
|
+
|
|
274
|
+
const eq: AssertEqual<
|
|
275
|
+
typeof result.alias,
|
|
276
|
+
{ name: string; tags: string[] } | null
|
|
277
|
+
> = true;
|
|
278
|
+
expect(eq).toBe(true);
|
|
279
|
+
|
|
280
|
+
expectQueryNotMutated(q);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('supports nesting', async () => {
|
|
284
|
+
const q = User.all();
|
|
285
|
+
|
|
286
|
+
const query = q.jsonRemove(q.jsonSet('data', ['tags'], ['tag']), [
|
|
287
|
+
'tags',
|
|
288
|
+
0,
|
|
289
|
+
]);
|
|
290
|
+
expectSql(
|
|
291
|
+
query.toSql(),
|
|
292
|
+
`
|
|
293
|
+
SELECT
|
|
294
|
+
jsonb_set("user"."data", '{tags}', $1) #- '{tags, 0}' AS "data"
|
|
295
|
+
FROM "user"
|
|
296
|
+
`,
|
|
297
|
+
['["tag"]'],
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const result = await query.take();
|
|
301
|
+
expect(result.data).toEqual({ name: 'value', tags: [] });
|
|
302
|
+
|
|
303
|
+
const eq: AssertEqual<
|
|
304
|
+
typeof result.data,
|
|
305
|
+
{ name: string; tags: string[] } | null
|
|
306
|
+
> = true;
|
|
307
|
+
expect(eq).toBe(true);
|
|
308
|
+
|
|
309
|
+
expectQueryNotMutated(q);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe('jsonPathQuery', () => {
|
|
314
|
+
it('should select json property', async () => {
|
|
315
|
+
const q = User.all();
|
|
316
|
+
|
|
317
|
+
const query = q.jsonPathQuery(
|
|
318
|
+
columnTypes.text(),
|
|
319
|
+
'data',
|
|
320
|
+
'$.name',
|
|
321
|
+
'name',
|
|
322
|
+
);
|
|
323
|
+
expectSql(
|
|
324
|
+
query.toSql(),
|
|
325
|
+
`
|
|
326
|
+
SELECT jsonb_path_query("user"."data", $1) AS "name"
|
|
327
|
+
FROM "user"
|
|
328
|
+
`,
|
|
329
|
+
['$.name'],
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
const result = await query.take();
|
|
333
|
+
expect(result.name).toBe('value');
|
|
334
|
+
|
|
335
|
+
const eq: AssertEqual<typeof result.name, string> = true;
|
|
336
|
+
expect(eq).toBe(true);
|
|
337
|
+
|
|
338
|
+
expectQueryNotMutated(q);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('optionally supports vars and silent options', () => {
|
|
342
|
+
const q = User.all();
|
|
343
|
+
|
|
344
|
+
const query = q.jsonPathQuery(
|
|
345
|
+
columnTypes.text(),
|
|
346
|
+
'data',
|
|
347
|
+
'$.name',
|
|
348
|
+
'name',
|
|
349
|
+
{
|
|
350
|
+
vars: 'vars',
|
|
351
|
+
silent: true,
|
|
352
|
+
},
|
|
353
|
+
);
|
|
354
|
+
expectSql(
|
|
355
|
+
query.toSql(),
|
|
356
|
+
`
|
|
357
|
+
SELECT jsonb_path_query("user"."data", $1, $2, true) AS "name"
|
|
358
|
+
FROM "user"
|
|
359
|
+
`,
|
|
360
|
+
['$.name', 'vars'],
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
expectQueryNotMutated(q);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('supports nesting', async () => {
|
|
367
|
+
const q = User.all();
|
|
368
|
+
|
|
369
|
+
const query = q.jsonPathQuery(
|
|
370
|
+
columnTypes.array(columnTypes.text()),
|
|
371
|
+
q.jsonSet('data', ['tags'], ['tag']),
|
|
372
|
+
'$.tags',
|
|
373
|
+
'tags',
|
|
374
|
+
);
|
|
375
|
+
expectSql(
|
|
376
|
+
query.toSql(),
|
|
377
|
+
`
|
|
378
|
+
SELECT
|
|
379
|
+
jsonb_path_query(
|
|
380
|
+
jsonb_set("user"."data", '{tags}', $1),
|
|
381
|
+
$2
|
|
382
|
+
) AS "tags"
|
|
383
|
+
FROM "user"
|
|
384
|
+
`,
|
|
385
|
+
['["tag"]', '$.tags'],
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
const result = await query.take();
|
|
389
|
+
expect(result.tags).toEqual(['tag']);
|
|
390
|
+
|
|
391
|
+
const eq: AssertEqual<typeof result.tags, string[]> = true;
|
|
392
|
+
expect(eq).toBe(true);
|
|
393
|
+
|
|
394
|
+
expectQueryNotMutated(q);
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
});
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { AddQuerySelect, Query, SetQueryReturnsValueOptional } from '../query';
|
|
2
|
+
import { pushQueryValue } from '../queryDataUtils';
|
|
3
|
+
import { ColumnType, StringColumn } from '../columnSchema';
|
|
4
|
+
import { JsonItem } from '../sql';
|
|
5
|
+
import { raw, StringKey } from '../common';
|
|
6
|
+
|
|
7
|
+
type JsonColumnName<T extends Pick<Query, 'selectable'>> = StringKey<
|
|
8
|
+
{
|
|
9
|
+
[K in keyof T['selectable']]: T['selectable'][K]['column']['dataType'] extends 'jsonb'
|
|
10
|
+
? K
|
|
11
|
+
: never;
|
|
12
|
+
}[keyof T['selectable']]
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
type ColumnOrJsonMethod<T extends Query> = JsonColumnName<T> | JsonItem;
|
|
16
|
+
|
|
17
|
+
type JsonSetResult<
|
|
18
|
+
T extends Query,
|
|
19
|
+
Column extends ColumnOrJsonMethod<T>,
|
|
20
|
+
As extends string,
|
|
21
|
+
Type extends ColumnType = Column extends keyof T['shape']
|
|
22
|
+
? T['shape'][Column]
|
|
23
|
+
: Column extends JsonItem
|
|
24
|
+
? Column['__json'][2]
|
|
25
|
+
: ColumnType,
|
|
26
|
+
> = JsonItem<As, Type> &
|
|
27
|
+
(Type extends ColumnType ? AddQuerySelect<T, Record<As, Type>> : T);
|
|
28
|
+
|
|
29
|
+
type JsonPathQueryResult<
|
|
30
|
+
T extends Query,
|
|
31
|
+
As extends string,
|
|
32
|
+
Type extends ColumnType,
|
|
33
|
+
> = JsonItem &
|
|
34
|
+
AddQuerySelect<
|
|
35
|
+
T,
|
|
36
|
+
{
|
|
37
|
+
[K in As]: Type;
|
|
38
|
+
}
|
|
39
|
+
>;
|
|
40
|
+
|
|
41
|
+
export class Json {
|
|
42
|
+
json<T extends Query>(
|
|
43
|
+
this: T,
|
|
44
|
+
): SetQueryReturnsValueOptional<T, StringColumn> {
|
|
45
|
+
return this.clone()._json();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_json<T extends Query>(
|
|
49
|
+
this: T,
|
|
50
|
+
): SetQueryReturnsValueOptional<T, StringColumn> {
|
|
51
|
+
const q = this._wrap(this.__model.clone()) as T;
|
|
52
|
+
q._getOptional(
|
|
53
|
+
raw<StringColumn>(
|
|
54
|
+
this.query.take
|
|
55
|
+
? `row_to_json("t".*)`
|
|
56
|
+
: `COALESCE(json_agg(row_to_json("t".*)), '[]')`,
|
|
57
|
+
),
|
|
58
|
+
);
|
|
59
|
+
delete q.query.take;
|
|
60
|
+
return q as unknown as SetQueryReturnsValueOptional<T, StringColumn>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
jsonSet<
|
|
64
|
+
T extends Query,
|
|
65
|
+
Column extends ColumnOrJsonMethod<T>,
|
|
66
|
+
As extends string = Column extends JsonItem ? Column['__json'][1] : Column,
|
|
67
|
+
>(
|
|
68
|
+
this: T,
|
|
69
|
+
column: Column,
|
|
70
|
+
path: Array<string | number>,
|
|
71
|
+
value: unknown,
|
|
72
|
+
options?: {
|
|
73
|
+
as?: As;
|
|
74
|
+
createIfMissing?: boolean;
|
|
75
|
+
},
|
|
76
|
+
): JsonSetResult<T, Column, As> {
|
|
77
|
+
const q = this.clone() as T;
|
|
78
|
+
return q._jsonSet(column, path, value, options);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
_jsonSet<
|
|
82
|
+
T extends Query,
|
|
83
|
+
Column extends ColumnOrJsonMethod<T>,
|
|
84
|
+
As extends string = Column extends JsonItem ? Column['__json'][1] : Column,
|
|
85
|
+
>(
|
|
86
|
+
this: T,
|
|
87
|
+
column: Column,
|
|
88
|
+
path: Array<string | number>,
|
|
89
|
+
value: unknown,
|
|
90
|
+
options?: {
|
|
91
|
+
as?: As;
|
|
92
|
+
createIfMissing?: boolean;
|
|
93
|
+
},
|
|
94
|
+
): JsonSetResult<T, Column, As> {
|
|
95
|
+
const json: JsonItem = {
|
|
96
|
+
__json: [
|
|
97
|
+
'set',
|
|
98
|
+
options?.as ??
|
|
99
|
+
(typeof column === 'string'
|
|
100
|
+
? column
|
|
101
|
+
: (column as JsonItem).__json[1]),
|
|
102
|
+
typeof column === 'string'
|
|
103
|
+
? this.shape[column]
|
|
104
|
+
: (column as JsonItem).__json[2],
|
|
105
|
+
column,
|
|
106
|
+
path,
|
|
107
|
+
value,
|
|
108
|
+
options,
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return Object.assign(
|
|
113
|
+
pushQueryValue(this, 'select', json),
|
|
114
|
+
json,
|
|
115
|
+
) as unknown as JsonSetResult<T, Column, As>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
jsonInsert<
|
|
119
|
+
T extends Query,
|
|
120
|
+
Column extends ColumnOrJsonMethod<T>,
|
|
121
|
+
As extends string = Column extends JsonItem ? Column['__json'][1] : Column,
|
|
122
|
+
>(
|
|
123
|
+
this: T,
|
|
124
|
+
...args: [
|
|
125
|
+
column: Column,
|
|
126
|
+
path: Array<string | number>,
|
|
127
|
+
value: unknown,
|
|
128
|
+
options?: {
|
|
129
|
+
as?: As;
|
|
130
|
+
insertAfter?: boolean;
|
|
131
|
+
},
|
|
132
|
+
]
|
|
133
|
+
): JsonSetResult<T, Column, As> {
|
|
134
|
+
const q = this.clone() as T;
|
|
135
|
+
return q._jsonInsert(...args);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
_jsonInsert<
|
|
139
|
+
T extends Query,
|
|
140
|
+
Column extends ColumnOrJsonMethod<T>,
|
|
141
|
+
As extends string = Column extends JsonItem ? Column['__json'][1] : Column,
|
|
142
|
+
>(
|
|
143
|
+
this: T,
|
|
144
|
+
column: Column,
|
|
145
|
+
path: Array<string | number>,
|
|
146
|
+
value: unknown,
|
|
147
|
+
options?: {
|
|
148
|
+
as?: As;
|
|
149
|
+
insertAfter?: boolean;
|
|
150
|
+
},
|
|
151
|
+
): JsonSetResult<T, Column, As> {
|
|
152
|
+
const json: JsonItem = {
|
|
153
|
+
__json: [
|
|
154
|
+
'insert',
|
|
155
|
+
options?.as ??
|
|
156
|
+
(typeof column === 'string'
|
|
157
|
+
? column
|
|
158
|
+
: (column as JsonItem).__json[1]),
|
|
159
|
+
typeof column === 'string'
|
|
160
|
+
? this.shape[column]
|
|
161
|
+
: (column as JsonItem).__json[2],
|
|
162
|
+
column,
|
|
163
|
+
path,
|
|
164
|
+
value,
|
|
165
|
+
options,
|
|
166
|
+
],
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
return Object.assign(
|
|
170
|
+
pushQueryValue(this, 'select', json),
|
|
171
|
+
json,
|
|
172
|
+
) as unknown as JsonSetResult<T, Column, As>;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
jsonRemove<
|
|
176
|
+
T extends Query,
|
|
177
|
+
Column extends ColumnOrJsonMethod<T>,
|
|
178
|
+
As extends string = Column extends JsonItem ? Column['__json'][1] : Column,
|
|
179
|
+
>(
|
|
180
|
+
this: T,
|
|
181
|
+
...args: [
|
|
182
|
+
column: Column,
|
|
183
|
+
path: Array<string | number>,
|
|
184
|
+
options?: { as?: As },
|
|
185
|
+
]
|
|
186
|
+
): JsonSetResult<T, Column, As> {
|
|
187
|
+
const q = this.clone() as T;
|
|
188
|
+
return q._jsonRemove(...args);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
_jsonRemove<
|
|
192
|
+
T extends Query,
|
|
193
|
+
Column extends ColumnOrJsonMethod<T>,
|
|
194
|
+
As extends string = Column extends JsonItem ? Column['__json'][1] : Column,
|
|
195
|
+
>(
|
|
196
|
+
this: T,
|
|
197
|
+
column: Column,
|
|
198
|
+
path: Array<string | number>,
|
|
199
|
+
options?: { as?: As },
|
|
200
|
+
): JsonSetResult<T, Column, As> {
|
|
201
|
+
const json: JsonItem = {
|
|
202
|
+
__json: [
|
|
203
|
+
'remove',
|
|
204
|
+
options?.as ??
|
|
205
|
+
(typeof column === 'string'
|
|
206
|
+
? column
|
|
207
|
+
: (column as JsonItem).__json[1]),
|
|
208
|
+
typeof column === 'string'
|
|
209
|
+
? this.shape[column]
|
|
210
|
+
: (column as JsonItem).__json[2],
|
|
211
|
+
column,
|
|
212
|
+
path,
|
|
213
|
+
],
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
return Object.assign(
|
|
217
|
+
pushQueryValue(this, 'select', json),
|
|
218
|
+
json,
|
|
219
|
+
) as unknown as JsonSetResult<T, Column, As>;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
jsonPathQuery<T extends Query, As extends string, Type extends ColumnType>(
|
|
223
|
+
this: T,
|
|
224
|
+
...args: [
|
|
225
|
+
type: Type,
|
|
226
|
+
column: ColumnOrJsonMethod<T>,
|
|
227
|
+
path: string,
|
|
228
|
+
as: As,
|
|
229
|
+
options?: {
|
|
230
|
+
vars?: string;
|
|
231
|
+
silent?: boolean;
|
|
232
|
+
},
|
|
233
|
+
]
|
|
234
|
+
): JsonPathQueryResult<T, As, Type> {
|
|
235
|
+
const q = this.clone() as T;
|
|
236
|
+
return q._jsonPathQuery(...args);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
_jsonPathQuery<T extends Query, As extends string, Type extends ColumnType>(
|
|
240
|
+
this: T,
|
|
241
|
+
type: Type,
|
|
242
|
+
column: ColumnOrJsonMethod<T>,
|
|
243
|
+
path: string,
|
|
244
|
+
as: As,
|
|
245
|
+
options?: {
|
|
246
|
+
vars?: string;
|
|
247
|
+
silent?: boolean;
|
|
248
|
+
},
|
|
249
|
+
): JsonPathQueryResult<T, As, Type> {
|
|
250
|
+
const json: JsonItem = {
|
|
251
|
+
__json: ['pathQuery', as, type, column, path, options],
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
return Object.assign(
|
|
255
|
+
pushQueryValue(this, 'select', json),
|
|
256
|
+
json,
|
|
257
|
+
) as unknown as JsonPathQueryResult<T, As, Type>;
|
|
258
|
+
}
|
|
259
|
+
}
|