@teamkeel/functions-runtime 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/.env.test +2 -0
- package/README.md +3 -0
- package/compose.yaml +10 -0
- package/package.json +33 -0
- package/src/ModelAPI.js +229 -0
- package/src/ModelAPI.test.js +920 -0
- package/src/QueryBuilder.js +95 -0
- package/src/QueryContext.js +90 -0
- package/src/RequestHeaders.js +21 -0
- package/src/applyAdditionalQueryConstraints.js +22 -0
- package/src/applyJoins.js +65 -0
- package/src/applyWhereConditions.js +70 -0
- package/src/casing.js +30 -0
- package/src/casing.test.js +25 -0
- package/src/consts.js +13 -0
- package/src/database.js +163 -0
- package/src/errors.js +116 -0
- package/src/handleJob.js +100 -0
- package/src/handleJob.test.js +271 -0
- package/src/handleRequest.js +124 -0
- package/src/handleRequest.test.js +360 -0
- package/src/index.d.ts +86 -0
- package/src/index.js +27 -0
- package/src/permissions.js +78 -0
- package/src/permissions.test.js +120 -0
- package/src/tracing.js +135 -0
- package/src/tracing.test.js +119 -0
- package/src/tryExecuteFunction.js +74 -0
- package/vite.config.js +7 -0
|
@@ -0,0 +1,920 @@
|
|
|
1
|
+
import { test, expect, beforeEach } from "vitest";
|
|
2
|
+
const { ModelAPI } = require("./ModelAPI");
|
|
3
|
+
const { sql } = require("kysely");
|
|
4
|
+
const { useDatabase } = require("./database");
|
|
5
|
+
const KSUID = require("ksuid");
|
|
6
|
+
|
|
7
|
+
let personAPI;
|
|
8
|
+
let postAPI;
|
|
9
|
+
let authorAPI;
|
|
10
|
+
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
const db = useDatabase();
|
|
13
|
+
|
|
14
|
+
await sql`
|
|
15
|
+
DROP TABLE IF EXISTS post;
|
|
16
|
+
DROP TABLE IF EXISTS person;
|
|
17
|
+
DROP TABLE IF EXISTS author;
|
|
18
|
+
|
|
19
|
+
CREATE TABLE person(
|
|
20
|
+
id text PRIMARY KEY,
|
|
21
|
+
name text UNIQUE,
|
|
22
|
+
married boolean,
|
|
23
|
+
favourite_number integer,
|
|
24
|
+
date timestamp
|
|
25
|
+
);
|
|
26
|
+
CREATE TABLE post(
|
|
27
|
+
id text PRIMARY KEY,
|
|
28
|
+
title text,
|
|
29
|
+
author_id text references person(id)
|
|
30
|
+
);
|
|
31
|
+
CREATE TABLE author(
|
|
32
|
+
id text PRIMARY KEY,
|
|
33
|
+
name text NOT NULL
|
|
34
|
+
);
|
|
35
|
+
`.execute(db);
|
|
36
|
+
|
|
37
|
+
const tableConfigMap = {
|
|
38
|
+
person: {
|
|
39
|
+
posts: {
|
|
40
|
+
relationshipType: "hasMany",
|
|
41
|
+
foreignKey: "author_id",
|
|
42
|
+
referencesTable: "post",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
post: {
|
|
46
|
+
author: {
|
|
47
|
+
relationshipType: "belongsTo",
|
|
48
|
+
foreignKey: "author_id",
|
|
49
|
+
referencesTable: "person",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
personAPI = new ModelAPI("person", undefined, tableConfigMap);
|
|
55
|
+
|
|
56
|
+
postAPI = new ModelAPI("post", undefined, tableConfigMap);
|
|
57
|
+
|
|
58
|
+
authorAPI = new ModelAPI("author", undefined, tableConfigMap);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("ModelAPI.create", async () => {
|
|
62
|
+
const row = await personAPI.create({
|
|
63
|
+
id: KSUID.randomSync().string,
|
|
64
|
+
name: "Jim",
|
|
65
|
+
married: false,
|
|
66
|
+
favouriteNumber: 10,
|
|
67
|
+
});
|
|
68
|
+
expect(row.name).toEqual("Jim");
|
|
69
|
+
expect(row.married).toEqual(false);
|
|
70
|
+
expect(row.favouriteNumber).toEqual(10);
|
|
71
|
+
expect(KSUID.parse(row.id).string).toEqual(row.id);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("ModelAPI.create - throws if not not null constraint violation", async () => {
|
|
75
|
+
await expect(
|
|
76
|
+
authorAPI.create({
|
|
77
|
+
id: KSUID.randomSync().string,
|
|
78
|
+
name: null,
|
|
79
|
+
})
|
|
80
|
+
).rejects.toThrow('null value in column "name" violates not-null constraint');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("ModelAPI.create - throws if database constraint fails", async () => {
|
|
84
|
+
const row = await personAPI.create({
|
|
85
|
+
id: KSUID.randomSync().string,
|
|
86
|
+
name: "Jim",
|
|
87
|
+
married: false,
|
|
88
|
+
favouriteNumber: 10,
|
|
89
|
+
});
|
|
90
|
+
const promise = personAPI.create({
|
|
91
|
+
id: KSUID.randomSync().string,
|
|
92
|
+
id: row.id,
|
|
93
|
+
name: "Jim",
|
|
94
|
+
married: false,
|
|
95
|
+
favouriteNumber: 10,
|
|
96
|
+
});
|
|
97
|
+
await expect(promise).rejects.toThrow(
|
|
98
|
+
`duplicate key value violates unique constraint "person_pkey"`
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("ModelAPI.findOne", async () => {
|
|
103
|
+
const created = await personAPI.create({
|
|
104
|
+
id: KSUID.randomSync().string,
|
|
105
|
+
name: "Jim",
|
|
106
|
+
married: false,
|
|
107
|
+
favouriteNumber: 10,
|
|
108
|
+
});
|
|
109
|
+
const row = await personAPI.findOne({
|
|
110
|
+
id: created.id,
|
|
111
|
+
});
|
|
112
|
+
expect(row).toEqual(created);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("ModelAPI.findOne - relationships - one to many", async () => {
|
|
116
|
+
const person = await personAPI.create({
|
|
117
|
+
id: KSUID.randomSync().string,
|
|
118
|
+
name: "Jim",
|
|
119
|
+
married: false,
|
|
120
|
+
favouriteNumber: 10,
|
|
121
|
+
});
|
|
122
|
+
const post = await postAPI.create({
|
|
123
|
+
id: KSUID.randomSync().string,
|
|
124
|
+
title: "My Post",
|
|
125
|
+
authorId: person.id,
|
|
126
|
+
});
|
|
127
|
+
const row = await personAPI.findOne({
|
|
128
|
+
posts: {
|
|
129
|
+
id: post.id,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
expect(row.name).toEqual("Jim");
|
|
133
|
+
expect(row.id).toEqual(person.id);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("ModelAPI.findOne - return null if not found", async () => {
|
|
137
|
+
const row = await personAPI.findOne({
|
|
138
|
+
id: "doesntexist",
|
|
139
|
+
});
|
|
140
|
+
expect(row).toEqual(null);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("ModelAPI.findMany", async () => {
|
|
144
|
+
await personAPI.create({
|
|
145
|
+
id: KSUID.randomSync().string,
|
|
146
|
+
name: "Jim",
|
|
147
|
+
married: false,
|
|
148
|
+
favouriteNumber: 10,
|
|
149
|
+
});
|
|
150
|
+
const bob = await personAPI.create({
|
|
151
|
+
id: KSUID.randomSync().string,
|
|
152
|
+
name: "Bob",
|
|
153
|
+
married: true,
|
|
154
|
+
favouriteNumber: 11,
|
|
155
|
+
});
|
|
156
|
+
const sally = await personAPI.create({
|
|
157
|
+
id: KSUID.randomSync().string,
|
|
158
|
+
name: "Sally",
|
|
159
|
+
married: true,
|
|
160
|
+
favouriteNumber: 12,
|
|
161
|
+
});
|
|
162
|
+
const rows = await personAPI.findMany({
|
|
163
|
+
where: {
|
|
164
|
+
married: true,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
expect(rows.length).toEqual(2);
|
|
168
|
+
expect(rows.map((x) => x.id).sort()).toEqual([bob.id, sally.id].sort());
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("ModelAPI.findMany - no where conditions", async () => {
|
|
172
|
+
await personAPI.create({
|
|
173
|
+
id: KSUID.randomSync().string,
|
|
174
|
+
name: "Jim",
|
|
175
|
+
});
|
|
176
|
+
await personAPI.create({
|
|
177
|
+
id: KSUID.randomSync().string,
|
|
178
|
+
name: "Bob",
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const rows = await personAPI.findMany({});
|
|
182
|
+
|
|
183
|
+
expect(rows.length).toEqual(2);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("ModelAPI.findMany - startsWith", async () => {
|
|
187
|
+
const jim = await personAPI.create({
|
|
188
|
+
id: KSUID.randomSync().string,
|
|
189
|
+
name: "Jim",
|
|
190
|
+
});
|
|
191
|
+
await personAPI.create({
|
|
192
|
+
id: KSUID.randomSync().string,
|
|
193
|
+
name: "Bob",
|
|
194
|
+
});
|
|
195
|
+
const rows = await personAPI.findMany({
|
|
196
|
+
where: {
|
|
197
|
+
name: {
|
|
198
|
+
startsWith: "Ji",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
expect(rows.length).toEqual(1);
|
|
203
|
+
expect(rows[0].id).toEqual(jim.id);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("ModelAPI.findMany - endsWith", async () => {
|
|
207
|
+
const jim = await personAPI.create({
|
|
208
|
+
id: KSUID.randomSync().string,
|
|
209
|
+
name: "Jim",
|
|
210
|
+
});
|
|
211
|
+
await personAPI.create({
|
|
212
|
+
id: KSUID.randomSync().string,
|
|
213
|
+
name: "Bob",
|
|
214
|
+
});
|
|
215
|
+
const rows = await personAPI.findMany({
|
|
216
|
+
where: {
|
|
217
|
+
name: {
|
|
218
|
+
endsWith: "im",
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
expect(rows.length).toEqual(1);
|
|
223
|
+
expect(rows[0].id).toEqual(jim.id);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("ModelAPI.findMany - contains", async () => {
|
|
227
|
+
const billy = await personAPI.create({
|
|
228
|
+
id: KSUID.randomSync().string,
|
|
229
|
+
name: "Billy",
|
|
230
|
+
});
|
|
231
|
+
const sally = await personAPI.create({
|
|
232
|
+
id: KSUID.randomSync().string,
|
|
233
|
+
name: "Sally",
|
|
234
|
+
});
|
|
235
|
+
await personAPI.create({
|
|
236
|
+
id: KSUID.randomSync().string,
|
|
237
|
+
name: "Jim",
|
|
238
|
+
});
|
|
239
|
+
const rows = await personAPI.findMany({
|
|
240
|
+
where: {
|
|
241
|
+
name: {
|
|
242
|
+
contains: "ll",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
expect(rows.length).toEqual(2);
|
|
247
|
+
expect(rows.map((x) => x.id).sort()).toEqual([billy.id, sally.id].sort());
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test("ModelAPI.findMany - oneOf", async () => {
|
|
251
|
+
const billy = await personAPI.create({
|
|
252
|
+
id: KSUID.randomSync().string,
|
|
253
|
+
name: "Billy",
|
|
254
|
+
});
|
|
255
|
+
const sally = await personAPI.create({
|
|
256
|
+
id: KSUID.randomSync().string,
|
|
257
|
+
name: "Sally",
|
|
258
|
+
});
|
|
259
|
+
await personAPI.create({
|
|
260
|
+
id: KSUID.randomSync().string,
|
|
261
|
+
name: "Jim",
|
|
262
|
+
});
|
|
263
|
+
const rows = await personAPI.findMany({
|
|
264
|
+
where: {
|
|
265
|
+
name: {
|
|
266
|
+
oneOf: ["Billy", "Sally"],
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
expect(rows.length).toEqual(2);
|
|
271
|
+
expect(rows.map((x) => x.id).sort()).toEqual([billy.id, sally.id].sort());
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test("ModelAPI.findMany - greaterThan", async () => {
|
|
275
|
+
await personAPI.create({
|
|
276
|
+
id: KSUID.randomSync().string,
|
|
277
|
+
favouriteNumber: 1,
|
|
278
|
+
});
|
|
279
|
+
const p = await personAPI.create({
|
|
280
|
+
id: KSUID.randomSync().string,
|
|
281
|
+
favouriteNumber: 2,
|
|
282
|
+
});
|
|
283
|
+
const rows = await personAPI.findMany({
|
|
284
|
+
where: {
|
|
285
|
+
favouriteNumber: {
|
|
286
|
+
greaterThan: 1,
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
expect(rows.length).toEqual(1);
|
|
291
|
+
expect(rows[0].id).toEqual(p.id);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("ModelAPI.findMany - greaterThanOrEquals", async () => {
|
|
295
|
+
await personAPI.create({
|
|
296
|
+
id: KSUID.randomSync().string,
|
|
297
|
+
favouriteNumber: 1,
|
|
298
|
+
});
|
|
299
|
+
const p = await personAPI.create({
|
|
300
|
+
id: KSUID.randomSync().string,
|
|
301
|
+
favouriteNumber: 2,
|
|
302
|
+
});
|
|
303
|
+
const p2 = await personAPI.create({
|
|
304
|
+
id: KSUID.randomSync().string,
|
|
305
|
+
favouriteNumber: 3,
|
|
306
|
+
});
|
|
307
|
+
const rows = await personAPI.findMany({
|
|
308
|
+
where: {
|
|
309
|
+
favouriteNumber: {
|
|
310
|
+
greaterThanOrEquals: 2,
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
expect(rows.length).toEqual(2);
|
|
315
|
+
expect(rows.map((x) => x.id).sort()).toEqual([p.id, p2.id].sort());
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test("ModelAPI.findMany - lessThan", async () => {
|
|
319
|
+
const p = await personAPI.create({
|
|
320
|
+
id: KSUID.randomSync().string,
|
|
321
|
+
favouriteNumber: 1,
|
|
322
|
+
});
|
|
323
|
+
await personAPI.create({
|
|
324
|
+
id: KSUID.randomSync().string,
|
|
325
|
+
favouriteNumber: 2,
|
|
326
|
+
});
|
|
327
|
+
const rows = await personAPI.findMany({
|
|
328
|
+
where: {
|
|
329
|
+
favouriteNumber: {
|
|
330
|
+
lessThan: 2,
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
expect(rows.length).toEqual(1);
|
|
335
|
+
expect(rows[0].id).toEqual(p.id);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("ModelAPI.findMany - lessThanOrEquals", async () => {
|
|
339
|
+
const p = await personAPI.create({
|
|
340
|
+
id: KSUID.randomSync().string,
|
|
341
|
+
favouriteNumber: 1,
|
|
342
|
+
});
|
|
343
|
+
const p2 = await personAPI.create({
|
|
344
|
+
id: KSUID.randomSync().string,
|
|
345
|
+
favouriteNumber: 2,
|
|
346
|
+
});
|
|
347
|
+
await personAPI.create({
|
|
348
|
+
id: KSUID.randomSync().string,
|
|
349
|
+
favouriteNumber: 3,
|
|
350
|
+
});
|
|
351
|
+
const rows = await personAPI.findMany({
|
|
352
|
+
where: {
|
|
353
|
+
favouriteNumber: {
|
|
354
|
+
lessThanOrEquals: 2,
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
expect(rows.length).toEqual(2);
|
|
359
|
+
expect(rows.map((x) => x.id).sort()).toEqual([p.id, p2.id].sort());
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
test("ModelAPI.findMany - before", async () => {
|
|
363
|
+
const p = await personAPI.create({
|
|
364
|
+
id: KSUID.randomSync().string,
|
|
365
|
+
date: new Date("2022-01-01"),
|
|
366
|
+
});
|
|
367
|
+
await personAPI.create({
|
|
368
|
+
id: KSUID.randomSync().string,
|
|
369
|
+
date: new Date("2022-01-02"),
|
|
370
|
+
});
|
|
371
|
+
const rows = await personAPI.findMany({
|
|
372
|
+
where: {
|
|
373
|
+
date: {
|
|
374
|
+
before: new Date("2022-01-02"),
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
expect(rows.length).toEqual(1);
|
|
379
|
+
expect(rows[0].id).toEqual(p.id);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test("ModelAPI.findMany - empty where", async () => {
|
|
383
|
+
const p = await personAPI.create({
|
|
384
|
+
id: KSUID.randomSync().string,
|
|
385
|
+
date: new Date("2022-01-01"),
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const p2 = await personAPI.create({
|
|
389
|
+
id: KSUID.randomSync().string,
|
|
390
|
+
date: new Date("2022-01-02"),
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// with no param specified at all
|
|
394
|
+
const rows = await personAPI.findMany();
|
|
395
|
+
|
|
396
|
+
expect(rows.map((r) => r.id).sort()).toEqual([p, p2].map((r) => r.id).sort());
|
|
397
|
+
|
|
398
|
+
// with empty object
|
|
399
|
+
const rows2 = await personAPI.findMany({});
|
|
400
|
+
|
|
401
|
+
expect(rows2.map((r) => r.id).sort()).toEqual(
|
|
402
|
+
[p, p2].map((r) => r.id).sort()
|
|
403
|
+
);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
test("ModelAPI.findMany - onOrBefore", async () => {
|
|
407
|
+
const p = await personAPI.create({
|
|
408
|
+
id: KSUID.randomSync().string,
|
|
409
|
+
date: new Date("2022-01-01"),
|
|
410
|
+
});
|
|
411
|
+
const p2 = await personAPI.create({
|
|
412
|
+
id: KSUID.randomSync().string,
|
|
413
|
+
date: new Date("2022-01-02"),
|
|
414
|
+
});
|
|
415
|
+
await personAPI.create({
|
|
416
|
+
id: KSUID.randomSync().string,
|
|
417
|
+
date: new Date("2022-01-03"),
|
|
418
|
+
});
|
|
419
|
+
const rows = await personAPI.findMany({
|
|
420
|
+
where: {
|
|
421
|
+
date: {
|
|
422
|
+
onOrBefore: new Date("2022-01-02"),
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
expect(rows.length).toEqual(2);
|
|
427
|
+
expect(rows.map((x) => x.id).sort()).toEqual([p.id, p2.id].sort());
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test("ModelAPI.findMany - limit", async () => {
|
|
431
|
+
await personAPI.create({
|
|
432
|
+
id: KSUID.randomSync().string,
|
|
433
|
+
name: "Jim",
|
|
434
|
+
married: false,
|
|
435
|
+
favouriteNumber: 10,
|
|
436
|
+
});
|
|
437
|
+
await personAPI.create({
|
|
438
|
+
id: KSUID.randomSync().string,
|
|
439
|
+
name: "Bob",
|
|
440
|
+
married: true,
|
|
441
|
+
favouriteNumber: 11,
|
|
442
|
+
});
|
|
443
|
+
await personAPI.create({
|
|
444
|
+
id: KSUID.randomSync().string,
|
|
445
|
+
name: "Sally",
|
|
446
|
+
married: true,
|
|
447
|
+
favouriteNumber: 12,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
const rows = await personAPI.findMany({
|
|
451
|
+
limit: 2,
|
|
452
|
+
orderBy: {
|
|
453
|
+
favouriteNumber: "asc",
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
expect(rows.map((r) => r.name)).toEqual(["Jim", "Bob"]);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
test("ModelAPI.findMany - orderBy", async () => {
|
|
461
|
+
await personAPI.create({
|
|
462
|
+
id: KSUID.randomSync().string,
|
|
463
|
+
name: "Jim",
|
|
464
|
+
married: false,
|
|
465
|
+
favouriteNumber: 10,
|
|
466
|
+
date: new Date(2023, 12, 29),
|
|
467
|
+
});
|
|
468
|
+
await personAPI.create({
|
|
469
|
+
id: KSUID.randomSync().string,
|
|
470
|
+
name: "Bob",
|
|
471
|
+
married: true,
|
|
472
|
+
favouriteNumber: 11,
|
|
473
|
+
date: new Date(2023, 12, 30),
|
|
474
|
+
});
|
|
475
|
+
await personAPI.create({
|
|
476
|
+
id: KSUID.randomSync().string,
|
|
477
|
+
name: "Sally",
|
|
478
|
+
married: true,
|
|
479
|
+
favouriteNumber: 12,
|
|
480
|
+
date: new Date(2023, 12, 31),
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
const ascendingNames = await personAPI.findMany({
|
|
484
|
+
orderBy: {
|
|
485
|
+
name: "asc",
|
|
486
|
+
},
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
expect(ascendingNames.map((r) => r.name)).toEqual(["Bob", "Jim", "Sally"]);
|
|
490
|
+
|
|
491
|
+
const descendingNames = await personAPI.findMany({
|
|
492
|
+
orderBy: {
|
|
493
|
+
name: "desc",
|
|
494
|
+
},
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
expect(descendingNames.map((r) => r.name)).toEqual(["Sally", "Jim", "Bob"]);
|
|
498
|
+
|
|
499
|
+
const ascendingFavouriteNumbers = await personAPI.findMany({
|
|
500
|
+
orderBy: {
|
|
501
|
+
favouriteNumber: "asc",
|
|
502
|
+
},
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
expect(ascendingFavouriteNumbers.map((r) => r.name)).toEqual([
|
|
506
|
+
"Jim",
|
|
507
|
+
"Bob",
|
|
508
|
+
"Sally",
|
|
509
|
+
]);
|
|
510
|
+
|
|
511
|
+
const descendingDates = await personAPI.findMany({
|
|
512
|
+
orderBy: {
|
|
513
|
+
date: "desc",
|
|
514
|
+
},
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
expect(descendingDates.map((r) => r.name)).toEqual(["Sally", "Bob", "Jim"]);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
test("ModelAPI.findMany - offset", async () => {
|
|
521
|
+
await personAPI.create({
|
|
522
|
+
id: KSUID.randomSync().string,
|
|
523
|
+
name: "Jim",
|
|
524
|
+
married: false,
|
|
525
|
+
favouriteNumber: 10,
|
|
526
|
+
date: new Date(2023, 12, 29),
|
|
527
|
+
});
|
|
528
|
+
await personAPI.create({
|
|
529
|
+
id: KSUID.randomSync().string,
|
|
530
|
+
name: "Bob",
|
|
531
|
+
married: true,
|
|
532
|
+
favouriteNumber: 11,
|
|
533
|
+
date: new Date(2023, 12, 30),
|
|
534
|
+
});
|
|
535
|
+
await personAPI.create({
|
|
536
|
+
id: KSUID.randomSync().string,
|
|
537
|
+
name: "Sally",
|
|
538
|
+
married: true,
|
|
539
|
+
favouriteNumber: 12,
|
|
540
|
+
date: new Date(2023, 12, 31),
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
const rows = await personAPI.findMany({
|
|
544
|
+
offset: 1,
|
|
545
|
+
limit: 2,
|
|
546
|
+
orderBy: {
|
|
547
|
+
name: "asc",
|
|
548
|
+
},
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
expect(rows.map((r) => r.name)).toEqual(["Jim", "Sally"]);
|
|
552
|
+
|
|
553
|
+
const rows2 = await personAPI.findMany({
|
|
554
|
+
offset: 2,
|
|
555
|
+
orderBy: {
|
|
556
|
+
name: "asc",
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
expect(rows2.map((r) => r.name)).toEqual(["Sally"]);
|
|
561
|
+
|
|
562
|
+
const rows3 = await personAPI.findMany({
|
|
563
|
+
offset: 1,
|
|
564
|
+
orderBy: {
|
|
565
|
+
name: "asc",
|
|
566
|
+
},
|
|
567
|
+
limit: 1,
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
expect(rows3.map((r) => r.name)).toEqual(["Jim"]);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
test("ModelAPI.findMany - after", async () => {
|
|
574
|
+
await personAPI.create({
|
|
575
|
+
id: KSUID.randomSync().string,
|
|
576
|
+
date: new Date("2022-01-01"),
|
|
577
|
+
});
|
|
578
|
+
const p = await personAPI.create({
|
|
579
|
+
id: KSUID.randomSync().string,
|
|
580
|
+
date: new Date("2022-01-02"),
|
|
581
|
+
});
|
|
582
|
+
const rows = await personAPI.findMany({
|
|
583
|
+
where: {
|
|
584
|
+
date: {
|
|
585
|
+
after: new Date("2022-01-01"),
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
});
|
|
589
|
+
expect(rows.length).toEqual(1);
|
|
590
|
+
expect(rows[0].id).toEqual(p.id);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
test("ModelAPI.findMany - onOrAfter", async () => {
|
|
594
|
+
await personAPI.create({
|
|
595
|
+
id: KSUID.randomSync().string,
|
|
596
|
+
date: new Date("2022-01-01"),
|
|
597
|
+
});
|
|
598
|
+
const p = await personAPI.create({
|
|
599
|
+
id: KSUID.randomSync().string,
|
|
600
|
+
date: new Date("2022-01-02"),
|
|
601
|
+
});
|
|
602
|
+
const p2 = await personAPI.create({
|
|
603
|
+
id: KSUID.randomSync().string,
|
|
604
|
+
date: new Date("2022-01-03"),
|
|
605
|
+
});
|
|
606
|
+
const rows = await personAPI.findMany({
|
|
607
|
+
where: {
|
|
608
|
+
date: {
|
|
609
|
+
onOrAfter: new Date("2022-01-02"),
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
});
|
|
613
|
+
expect(rows.length).toEqual(2);
|
|
614
|
+
expect(rows.map((x) => x.id).sort()).toEqual([p.id, p2.id].sort());
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
test("ModelAPI.findMany - equals", async () => {
|
|
618
|
+
const p = await personAPI.create({
|
|
619
|
+
id: KSUID.randomSync().string,
|
|
620
|
+
name: "Jim",
|
|
621
|
+
});
|
|
622
|
+
await personAPI.create({
|
|
623
|
+
id: KSUID.randomSync().string,
|
|
624
|
+
name: "Sally",
|
|
625
|
+
});
|
|
626
|
+
const rows = await personAPI.findMany({
|
|
627
|
+
where: {
|
|
628
|
+
name: {
|
|
629
|
+
equals: "Jim",
|
|
630
|
+
},
|
|
631
|
+
},
|
|
632
|
+
});
|
|
633
|
+
expect(rows.length).toEqual(1);
|
|
634
|
+
expect(rows[0].id).toEqual(p.id);
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
test("ModelAPI.findMany - notEquals", async () => {
|
|
638
|
+
const p = await personAPI.create({
|
|
639
|
+
id: KSUID.randomSync().string,
|
|
640
|
+
name: "Jim",
|
|
641
|
+
});
|
|
642
|
+
await personAPI.create({
|
|
643
|
+
id: KSUID.randomSync().string,
|
|
644
|
+
name: "Sally",
|
|
645
|
+
});
|
|
646
|
+
const rows = await personAPI.findMany({
|
|
647
|
+
where: {
|
|
648
|
+
name: {
|
|
649
|
+
notEquals: "Sally",
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
});
|
|
653
|
+
expect(rows.length).toEqual(1);
|
|
654
|
+
expect(rows[0].id).toEqual(p.id);
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
test("ModelAPI.findMany - complex query", async () => {
|
|
658
|
+
const p = await personAPI.create({
|
|
659
|
+
id: KSUID.randomSync().string,
|
|
660
|
+
name: "Jake",
|
|
661
|
+
favouriteNumber: 8,
|
|
662
|
+
date: new Date("2021-12-31"),
|
|
663
|
+
});
|
|
664
|
+
await personAPI.create({
|
|
665
|
+
id: KSUID.randomSync().string,
|
|
666
|
+
name: "Jane",
|
|
667
|
+
favouriteNumber: 12,
|
|
668
|
+
date: new Date("2022-01-11"),
|
|
669
|
+
});
|
|
670
|
+
const p2 = await personAPI.create({
|
|
671
|
+
id: KSUID.randomSync().string,
|
|
672
|
+
name: "Billy",
|
|
673
|
+
favouriteNumber: 16,
|
|
674
|
+
date: new Date("2022-01-05"),
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
const rows = await personAPI
|
|
678
|
+
// Will match Jake
|
|
679
|
+
.where({
|
|
680
|
+
name: {
|
|
681
|
+
startsWith: "J",
|
|
682
|
+
endsWith: "e",
|
|
683
|
+
},
|
|
684
|
+
favouriteNumber: {
|
|
685
|
+
lessThan: 10,
|
|
686
|
+
},
|
|
687
|
+
})
|
|
688
|
+
// Will match Billy
|
|
689
|
+
.orWhere({
|
|
690
|
+
date: {
|
|
691
|
+
after: new Date("2022-01-01"),
|
|
692
|
+
before: new Date("2022-01-10"),
|
|
693
|
+
},
|
|
694
|
+
})
|
|
695
|
+
.findMany();
|
|
696
|
+
expect(rows.length).toEqual(2);
|
|
697
|
+
expect(rows.map((x) => x.id).sort()).toEqual([p.id, p2.id].sort());
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
test("ModelAPI.findMany - relationships - one to many", async () => {
|
|
701
|
+
const person = await personAPI.create({
|
|
702
|
+
id: KSUID.randomSync().string,
|
|
703
|
+
name: "Jim",
|
|
704
|
+
});
|
|
705
|
+
const person2 = await personAPI.create({
|
|
706
|
+
id: KSUID.randomSync().string,
|
|
707
|
+
name: "Bob",
|
|
708
|
+
});
|
|
709
|
+
const post1 = await postAPI.create({
|
|
710
|
+
id: KSUID.randomSync().string,
|
|
711
|
+
title: "My First Post",
|
|
712
|
+
authorId: person.id,
|
|
713
|
+
});
|
|
714
|
+
const post2 = await postAPI.create({
|
|
715
|
+
id: KSUID.randomSync().string,
|
|
716
|
+
title: "My Second Post",
|
|
717
|
+
authorId: person.id,
|
|
718
|
+
});
|
|
719
|
+
await postAPI.create({
|
|
720
|
+
id: KSUID.randomSync().string,
|
|
721
|
+
title: "My Third Post",
|
|
722
|
+
authorId: person2.id,
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
const posts = await postAPI.findMany({
|
|
726
|
+
where: {
|
|
727
|
+
author: {
|
|
728
|
+
name: "Jim",
|
|
729
|
+
},
|
|
730
|
+
},
|
|
731
|
+
});
|
|
732
|
+
expect(posts.length).toEqual(2);
|
|
733
|
+
expect(posts.map((x) => x.id).sort()).toEqual([post1.id, post2.id].sort());
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
test("ModelAPI.findMany - relationships - many to one", async () => {
|
|
737
|
+
const person = await personAPI.create({
|
|
738
|
+
id: KSUID.randomSync().string,
|
|
739
|
+
name: "Jim",
|
|
740
|
+
});
|
|
741
|
+
await postAPI.create({
|
|
742
|
+
id: KSUID.randomSync().string,
|
|
743
|
+
title: "My First Post",
|
|
744
|
+
authorId: person.id,
|
|
745
|
+
});
|
|
746
|
+
await postAPI.create({
|
|
747
|
+
id: KSUID.randomSync().string,
|
|
748
|
+
title: "My Second Post",
|
|
749
|
+
authorId: person.id,
|
|
750
|
+
});
|
|
751
|
+
await postAPI.create({
|
|
752
|
+
id: KSUID.randomSync().string,
|
|
753
|
+
title: "My Second Post",
|
|
754
|
+
authorId: person.id,
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
const people = await personAPI.findMany({
|
|
758
|
+
where: {
|
|
759
|
+
posts: {
|
|
760
|
+
title: {
|
|
761
|
+
startsWith: "My ",
|
|
762
|
+
endsWith: " Post",
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
},
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
// This tests that many to one joins work for findMany() but also
|
|
769
|
+
// that the same row is not returned more than once e.g. Jim has
|
|
770
|
+
// three posts but should only be returned once
|
|
771
|
+
expect(people.length).toEqual(1);
|
|
772
|
+
expect(people[0].id).toEqual(person.id);
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
test("ModelAPI.findMany - relationships - duplicate joins handled", async () => {
|
|
776
|
+
const person = await personAPI.create({
|
|
777
|
+
id: KSUID.randomSync().string,
|
|
778
|
+
name: "Jim",
|
|
779
|
+
});
|
|
780
|
+
const person2 = await personAPI.create({
|
|
781
|
+
id: KSUID.randomSync().string,
|
|
782
|
+
name: "Bob",
|
|
783
|
+
});
|
|
784
|
+
const post1 = await postAPI.create({
|
|
785
|
+
id: KSUID.randomSync().string,
|
|
786
|
+
title: "My First Post",
|
|
787
|
+
authorId: person.id,
|
|
788
|
+
});
|
|
789
|
+
const post2 = await postAPI.create({
|
|
790
|
+
id: KSUID.randomSync().string,
|
|
791
|
+
title: "My Second Post",
|
|
792
|
+
authorId: person2.id,
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
const posts = await postAPI
|
|
796
|
+
.where({
|
|
797
|
+
author: {
|
|
798
|
+
name: "Jim",
|
|
799
|
+
},
|
|
800
|
+
})
|
|
801
|
+
.orWhere({
|
|
802
|
+
author: {
|
|
803
|
+
name: "Bob",
|
|
804
|
+
},
|
|
805
|
+
})
|
|
806
|
+
.findMany();
|
|
807
|
+
|
|
808
|
+
expect(posts.length).toEqual(2);
|
|
809
|
+
expect(posts.map((x) => x.id).sort()).toEqual([post1.id, post2.id].sort());
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
test("ModelAPI.update", async () => {
|
|
813
|
+
let jim = await personAPI.create({
|
|
814
|
+
id: KSUID.randomSync().string,
|
|
815
|
+
name: "Jim",
|
|
816
|
+
married: false,
|
|
817
|
+
favouriteNumber: 10,
|
|
818
|
+
});
|
|
819
|
+
let bob = await personAPI.create({
|
|
820
|
+
id: KSUID.randomSync().string,
|
|
821
|
+
name: "Bob",
|
|
822
|
+
married: false,
|
|
823
|
+
favouriteNumber: 11,
|
|
824
|
+
});
|
|
825
|
+
jim = await personAPI.update(
|
|
826
|
+
{
|
|
827
|
+
id: jim.id,
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
married: true,
|
|
831
|
+
}
|
|
832
|
+
);
|
|
833
|
+
expect(jim.married).toEqual(true);
|
|
834
|
+
expect(jim.name).toEqual("Jim");
|
|
835
|
+
|
|
836
|
+
bob = await personAPI.findOne({ id: bob.id });
|
|
837
|
+
expect(bob.married).toEqual(false);
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
test("ModelAPI.update - throws if not found", async () => {
|
|
841
|
+
const result = personAPI.update(
|
|
842
|
+
{
|
|
843
|
+
id: "doesntexist",
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
married: true,
|
|
847
|
+
}
|
|
848
|
+
);
|
|
849
|
+
await expect(result).rejects.toThrow("no result");
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
test("ModelAPI.update - throws if not not null constraint violation", async () => {
|
|
853
|
+
const jim = await authorAPI.create({
|
|
854
|
+
id: KSUID.randomSync().string,
|
|
855
|
+
name: "jim",
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
const result = authorAPI.update(
|
|
859
|
+
{
|
|
860
|
+
id: jim.id,
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
name: null,
|
|
864
|
+
}
|
|
865
|
+
);
|
|
866
|
+
|
|
867
|
+
await expect(result).rejects.toThrow(
|
|
868
|
+
'null value in column "name" violates not-null constraint'
|
|
869
|
+
);
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
test("ModelAPI.delete", async () => {
|
|
873
|
+
const jim = await personAPI.create({
|
|
874
|
+
id: KSUID.randomSync().string,
|
|
875
|
+
name: "Jim",
|
|
876
|
+
});
|
|
877
|
+
const id = jim.id;
|
|
878
|
+
const deletedId = await personAPI.delete({
|
|
879
|
+
name: "Jim",
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
expect(deletedId).toEqual(id);
|
|
883
|
+
await expect(personAPI.findOne({ id })).resolves.toEqual(null);
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
test("ModelAPI chained findMany with offset/limit/order by", async () => {
|
|
887
|
+
await postAPI.create({
|
|
888
|
+
id: KSUID.randomSync().string,
|
|
889
|
+
title: "adam",
|
|
890
|
+
});
|
|
891
|
+
await postAPI.create({
|
|
892
|
+
id: KSUID.randomSync().string,
|
|
893
|
+
title: "dave",
|
|
894
|
+
});
|
|
895
|
+
const three = await postAPI.create({
|
|
896
|
+
id: KSUID.randomSync().string,
|
|
897
|
+
title: "jon",
|
|
898
|
+
});
|
|
899
|
+
const four = await postAPI.create({
|
|
900
|
+
id: KSUID.randomSync().string,
|
|
901
|
+
title: "jon bretman",
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
const results = await postAPI
|
|
905
|
+
.where({ title: { equals: "adam" } })
|
|
906
|
+
.orWhere({
|
|
907
|
+
title: { startsWith: "jon" },
|
|
908
|
+
})
|
|
909
|
+
.findMany({
|
|
910
|
+
limit: 3,
|
|
911
|
+
offset: 1,
|
|
912
|
+
orderBy: {
|
|
913
|
+
title: "asc",
|
|
914
|
+
},
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
// because we've offset by 1, adam should not appear in the results even though
|
|
918
|
+
// the query constraints match adam
|
|
919
|
+
expect(results).toEqual([three, four]);
|
|
920
|
+
});
|