@terreno/api 0.0.11-beta.1 → 0.0.12

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.
@@ -0,0 +1,805 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __generator = (this && this.__generator) || function (thisArg, body) {
45
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
46
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
47
+ function verb(n) { return function (v) { return step([n, v]); }; }
48
+ function step(op) {
49
+ if (f) throw new TypeError("Generator is already executing.");
50
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
51
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
52
+ if (y = 0, t) op = [op[0] & 2, t.value];
53
+ switch (op[0]) {
54
+ case 0: case 1: t = op; break;
55
+ case 4: _.label++; return { value: op[1], done: false };
56
+ case 5: _.label++; y = op[1]; op = [0]; continue;
57
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
58
+ default:
59
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
60
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
61
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
62
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
63
+ if (t[2]) _.ops.pop();
64
+ _.trys.pop(); continue;
65
+ }
66
+ op = body.call(thisArg, _);
67
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
68
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
+ }
70
+ };
71
+ var __read = (this && this.__read) || function (o, n) {
72
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
73
+ if (!m) return o;
74
+ var i = m.call(o), r, ar = [], e;
75
+ try {
76
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
77
+ }
78
+ catch (error) { e = { error: error }; }
79
+ finally {
80
+ try {
81
+ if (r && !r.done && (m = i["return"])) m.call(i);
82
+ }
83
+ finally { if (e) throw e.error; }
84
+ }
85
+ return ar;
86
+ };
87
+ var __importDefault = (this && this.__importDefault) || function (mod) {
88
+ return (mod && mod.__esModule) ? mod : { "default": mod };
89
+ };
90
+ Object.defineProperty(exports, "__esModule", { value: true });
91
+ var bun_test_1 = require("bun:test");
92
+ var Sentry = __importStar(require("@sentry/node"));
93
+ var qs_1 = __importDefault(require("qs"));
94
+ var supertest_1 = __importDefault(require("supertest"));
95
+ var api_1 = require("./api");
96
+ var auth_1 = require("./auth");
97
+ var expressServer_1 = require("./expressServer");
98
+ var permissions_1 = require("./permissions");
99
+ var tests_1 = require("./tests");
100
+ (0, bun_test_1.describe)("query and list methods", function () {
101
+ var server;
102
+ var app;
103
+ var notAdmin;
104
+ var admin;
105
+ var adminOther;
106
+ var agent;
107
+ var spinach;
108
+ var apple;
109
+ var carrots;
110
+ var pizza;
111
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
112
+ var results;
113
+ var _a, _b;
114
+ return __generator(this, function (_c) {
115
+ switch (_c.label) {
116
+ case 0: return [4 /*yield*/, (0, tests_1.setupDb)()];
117
+ case 1:
118
+ _a = __read.apply(void 0, [_c.sent(), 3]), admin = _a[0], notAdmin = _a[1], adminOther = _a[2];
119
+ return [4 /*yield*/, Promise.all([
120
+ tests_1.FoodModel.create({
121
+ calories: 1,
122
+ created: new Date("2021-12-03T00:00:20.000Z"),
123
+ eatenBy: [admin._id],
124
+ hidden: false,
125
+ lastEatenWith: {
126
+ dressing: new Date("2021-12-03T19:00:30.000Z"),
127
+ },
128
+ name: "Spinach",
129
+ ownerId: notAdmin._id,
130
+ source: {
131
+ dateAdded: "2023-12-13T12:30:00.000Z",
132
+ href: "https://www.google.com",
133
+ name: "Brand",
134
+ },
135
+ }),
136
+ tests_1.FoodModel.create({
137
+ calories: 100,
138
+ created: new Date("2021-12-03T00:00:30.000Z"),
139
+ hidden: true,
140
+ name: "Apple",
141
+ ownerId: admin._id,
142
+ tags: ["healthy"],
143
+ }),
144
+ tests_1.FoodModel.create({
145
+ calories: 100,
146
+ created: new Date("2021-12-03T00:00:00.000Z"),
147
+ eatenBy: [admin._id, notAdmin._id],
148
+ hidden: false,
149
+ name: "Carrots",
150
+ ownerId: admin._id,
151
+ source: {
152
+ name: "USDA",
153
+ },
154
+ tags: ["healthy", "cheap"],
155
+ }),
156
+ tests_1.FoodModel.create({
157
+ calories: 400,
158
+ created: new Date("2021-12-03T00:00:10.000Z"),
159
+ eatenBy: [adminOther._id],
160
+ hidden: false,
161
+ name: "Pizza",
162
+ ownerId: admin._id,
163
+ tags: ["cheap"],
164
+ }),
165
+ ])];
166
+ case 2:
167
+ results = (_c.sent());
168
+ _b = __read(results, 4), spinach = _b[0], apple = _b[1], carrots = _b[2], pizza = _b[3];
169
+ app = (0, tests_1.getBaseServer)();
170
+ (0, auth_1.setupAuth)(app, tests_1.UserModel);
171
+ (0, auth_1.addAuthRoutes)(app, tests_1.UserModel);
172
+ app.use(expressServer_1.logRequests);
173
+ app.use("/food", (0, api_1.modelRouter)(tests_1.FoodModel, {
174
+ allowAnonymous: true,
175
+ defaultLimit: 2,
176
+ defaultQueryParams: { hidden: false },
177
+ maxLimit: 3,
178
+ permissions: {
179
+ create: [permissions_1.Permissions.IsAuthenticated],
180
+ delete: [permissions_1.Permissions.IsAdmin],
181
+ list: [permissions_1.Permissions.IsAny],
182
+ read: [permissions_1.Permissions.IsAny],
183
+ update: [permissions_1.Permissions.IsOwner],
184
+ },
185
+ populatePaths: [{ path: "ownerId" }],
186
+ queryFields: ["hidden", "name", "calories", "created", "source.name", "tags", "eatenBy"],
187
+ sort: { created: "descending" },
188
+ }));
189
+ server = (0, supertest_1.default)(app);
190
+ return [4 /*yield*/, (0, tests_1.authAsUser)(app, "notAdmin")];
191
+ case 3:
192
+ agent = _c.sent();
193
+ return [2 /*return*/];
194
+ }
195
+ });
196
+ }); });
197
+ (0, bun_test_1.it)("read default", function () { return __awaiter(void 0, void 0, void 0, function () {
198
+ var res;
199
+ return __generator(this, function (_a) {
200
+ switch (_a.label) {
201
+ case 0: return [4 /*yield*/, agent.get("/food/".concat(spinach._id)).expect(200)];
202
+ case 1:
203
+ res = _a.sent();
204
+ (0, bun_test_1.expect)(res.body.data._id).toBe(spinach._id.toString());
205
+ (0, bun_test_1.expect)(res.body.data.ownerId._id).toBe(notAdmin.id);
206
+ (0, bun_test_1.expect)(res.body.data.lastEatenWith).toEqual({
207
+ dressing: "2021-12-03T19:00:30.000Z",
208
+ });
209
+ return [2 /*return*/];
210
+ }
211
+ });
212
+ }); });
213
+ (0, bun_test_1.it)("list default", function () { return __awaiter(void 0, void 0, void 0, function () {
214
+ var res;
215
+ return __generator(this, function (_a) {
216
+ switch (_a.label) {
217
+ case 0: return [4 /*yield*/, agent.get("/food").expect(200)];
218
+ case 1:
219
+ res = _a.sent();
220
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(2);
221
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(spinach.id);
222
+ (0, bun_test_1.expect)(res.body.data[0].ownerId._id).toBe(notAdmin.id);
223
+ (0, bun_test_1.expect)(res.body.data[1].id).toBe(pizza.id);
224
+ (0, bun_test_1.expect)(res.body.data[1].ownerId._id).toBe(admin.id);
225
+ (0, bun_test_1.expect)(res.body.data[0].lastEatenWith).toEqual({
226
+ dressing: "2021-12-03T19:00:30.000Z",
227
+ });
228
+ (0, bun_test_1.expect)(res.body.data[1].lastEatenWith).toEqual(undefined);
229
+ (0, bun_test_1.expect)(res.body.more).toBe(true);
230
+ (0, bun_test_1.expect)(res.body.total).toBe(3);
231
+ return [2 /*return*/];
232
+ }
233
+ });
234
+ }); });
235
+ (0, bun_test_1.it)("list limit", function () { return __awaiter(void 0, void 0, void 0, function () {
236
+ var res;
237
+ return __generator(this, function (_a) {
238
+ switch (_a.label) {
239
+ case 0: return [4 /*yield*/, agent.get("/food?limit=1").expect(200)];
240
+ case 1:
241
+ res = _a.sent();
242
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
243
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(spinach.id);
244
+ (0, bun_test_1.expect)(res.body.data[0].ownerId._id).toBe(notAdmin.id);
245
+ (0, bun_test_1.expect)(res.body.more).toBe(true);
246
+ (0, bun_test_1.expect)(res.body.total).toBe(3);
247
+ return [2 /*return*/];
248
+ }
249
+ });
250
+ }); });
251
+ (0, bun_test_1.it)("list limit over", function () { return __awaiter(void 0, void 0, void 0, function () {
252
+ var res;
253
+ return __generator(this, function (_a) {
254
+ switch (_a.label) {
255
+ case 0: return [4 /*yield*/, tests_1.FoodModel.create({
256
+ calories: 400,
257
+ created: new Date("2021-12-02T00:00:10.000Z"),
258
+ hidden: false,
259
+ name: "Pizza",
260
+ ownerId: admin._id,
261
+ })];
262
+ case 1:
263
+ _a.sent();
264
+ return [4 /*yield*/, agent.get("/food?limit=4").expect(200)];
265
+ case 2:
266
+ res = _a.sent();
267
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(3);
268
+ (0, bun_test_1.expect)(res.body.more).toBe(true);
269
+ (0, bun_test_1.expect)(res.body.total).toBe(4);
270
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(spinach.id);
271
+ (0, bun_test_1.expect)(res.body.data[1].id).toBe(pizza.id);
272
+ (0, bun_test_1.expect)(res.body.data[2].id).toBe(carrots.id);
273
+ (0, bun_test_1.expect)(Sentry.captureMessage).toHaveBeenCalledWith('More than 3 results returned for foods without pagination, data may be silently truncated. req.query: {"limit":"4"}');
274
+ return [2 /*return*/];
275
+ }
276
+ });
277
+ }); });
278
+ (0, bun_test_1.it)("list page", function () { return __awaiter(void 0, void 0, void 0, function () {
279
+ var res;
280
+ return __generator(this, function (_a) {
281
+ switch (_a.label) {
282
+ case 0: return [4 /*yield*/, agent.get("/food?limit=1&page=2").expect(200)];
283
+ case 1:
284
+ res = _a.sent();
285
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
286
+ (0, bun_test_1.expect)(res.body.more).toBe(true);
287
+ (0, bun_test_1.expect)(res.body.total).toBe(3);
288
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(pizza.id);
289
+ return [2 /*return*/];
290
+ }
291
+ });
292
+ }); });
293
+ (0, bun_test_1.it)("list page 0 ", function () { return __awaiter(void 0, void 0, void 0, function () {
294
+ var res;
295
+ return __generator(this, function (_a) {
296
+ switch (_a.label) {
297
+ case 0: return [4 /*yield*/, agent.get("/food?limit=1&page=0").expect(400)];
298
+ case 1:
299
+ res = _a.sent();
300
+ (0, bun_test_1.expect)(res.body.title).toBe("Invalid page: 0");
301
+ return [2 /*return*/];
302
+ }
303
+ });
304
+ }); });
305
+ (0, bun_test_1.it)("list page with garbage ", function () { return __awaiter(void 0, void 0, void 0, function () {
306
+ var res;
307
+ return __generator(this, function (_a) {
308
+ switch (_a.label) {
309
+ case 0: return [4 /*yield*/, agent.get("/food?limit=1&page=abc").expect(400)];
310
+ case 1:
311
+ res = _a.sent();
312
+ (0, bun_test_1.expect)(res.body.title).toBe("Invalid page: abc");
313
+ return [2 /*return*/];
314
+ }
315
+ });
316
+ }); });
317
+ (0, bun_test_1.it)("list page over", function () { return __awaiter(void 0, void 0, void 0, function () {
318
+ var res;
319
+ return __generator(this, function (_a) {
320
+ switch (_a.label) {
321
+ case 0: return [4 /*yield*/, agent.get("/food?limit=1&page=5").expect(200)];
322
+ case 1:
323
+ res = _a.sent();
324
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(0);
325
+ (0, bun_test_1.expect)(res.body.more).toBe(false);
326
+ (0, bun_test_1.expect)(res.body.total).toBe(3);
327
+ return [2 /*return*/];
328
+ }
329
+ });
330
+ }); });
331
+ (0, bun_test_1.it)("list query params", function () { return __awaiter(void 0, void 0, void 0, function () {
332
+ var res;
333
+ return __generator(this, function (_a) {
334
+ switch (_a.label) {
335
+ case 0: return [4 /*yield*/, agent.get("/food?hidden=true").expect(200)];
336
+ case 1:
337
+ res = _a.sent();
338
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
339
+ (0, bun_test_1.expect)(res.body.more).toBe(false);
340
+ (0, bun_test_1.expect)(res.body.total).toBe(1);
341
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(apple.id);
342
+ return [2 /*return*/];
343
+ }
344
+ });
345
+ }); });
346
+ (0, bun_test_1.it)("list query params not in list", function () { return __awaiter(void 0, void 0, void 0, function () {
347
+ var res;
348
+ return __generator(this, function (_a) {
349
+ switch (_a.label) {
350
+ case 0: return [4 /*yield*/, agent.get("/food?ownerId=".concat(admin._id)).expect(400)];
351
+ case 1:
352
+ res = _a.sent();
353
+ (0, bun_test_1.expect)(res.body.title).toBe("ownerId is not allowed as a query param.");
354
+ return [2 /*return*/];
355
+ }
356
+ });
357
+ }); });
358
+ (0, bun_test_1.it)("list query by nested param", function () { return __awaiter(void 0, void 0, void 0, function () {
359
+ var res;
360
+ return __generator(this, function (_a) {
361
+ switch (_a.label) {
362
+ case 0: return [4 /*yield*/, agent.get("/food?source.name=USDA").expect(200)];
363
+ case 1:
364
+ res = _a.sent();
365
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
366
+ (0, bun_test_1.expect)(res.body.total).toBe(1);
367
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(carrots.id);
368
+ return [2 /*return*/];
369
+ }
370
+ });
371
+ }); });
372
+ (0, bun_test_1.it)("query by date", function () { return __awaiter(void 0, void 0, void 0, function () {
373
+ var authRes, token, res, createdDates;
374
+ return __generator(this, function (_a) {
375
+ switch (_a.label) {
376
+ case 0: return [4 /*yield*/, server
377
+ .post("/auth/login")
378
+ .send({ email: "admin@example.com", password: "securePassword" })
379
+ .expect(200)];
380
+ case 1:
381
+ authRes = _a.sent();
382
+ token = authRes.body.data.token;
383
+ return [4 /*yield*/, server
384
+ .get("/food?limit=3&".concat(qs_1.default.stringify({
385
+ created: {
386
+ $gte: "2021-12-03T00:00:00.000Z",
387
+ $lte: "2021-12-03T00:00:20.000Z",
388
+ },
389
+ })))
390
+ .set("authorization", "Bearer ".concat(token))
391
+ .expect(200)];
392
+ case 2:
393
+ res = _a.sent();
394
+ (0, bun_test_1.expect)(res.body.data.map(function (d) { return d.created; })).toEqual(bun_test_1.expect.arrayContaining([
395
+ "2021-12-03T00:00:20.000Z",
396
+ "2021-12-03T00:00:10.000Z",
397
+ "2021-12-03T00:00:00.000Z",
398
+ ]));
399
+ (0, bun_test_1.expect)(res.body.data.map(function (d) { return d.created; })).toHaveLength(3);
400
+ return [4 /*yield*/, server
401
+ .get("/food?limit=3&".concat(qs_1.default.stringify({
402
+ created: {
403
+ $gte: "2021-12-03T00:00:00.000Z",
404
+ $lt: "2021-12-03T00:00:20.000Z",
405
+ },
406
+ })))
407
+ .set("authorization", "Bearer ".concat(token))
408
+ .expect(200)];
409
+ case 3:
410
+ res = _a.sent();
411
+ (0, bun_test_1.expect)(res.body.data.map(function (d) { return d.created; })).toEqual(bun_test_1.expect.arrayContaining(["2021-12-03T00:00:10.000Z", "2021-12-03T00:00:00.000Z"]));
412
+ (0, bun_test_1.expect)(res.body.data.map(function (d) { return d.created; })).toHaveLength(2);
413
+ return [4 /*yield*/, server
414
+ .get("/food?limit=3&".concat(qs_1.default.stringify({
415
+ created: {
416
+ $gt: "2021-12-03T00:00:00.000Z",
417
+ $lt: "2021-12-03T00:00:20.000Z",
418
+ },
419
+ })))
420
+ .set("authorization", "Bearer ".concat(token))
421
+ .expect(200)];
422
+ case 4:
423
+ res = _a.sent();
424
+ createdDates = res.body.data.map(function (d) { return d.created; });
425
+ (0, bun_test_1.expect)(createdDates).toEqual(bun_test_1.expect.arrayContaining(["2021-12-03T00:00:10.000Z"]));
426
+ (0, bun_test_1.expect)(createdDates).toHaveLength(1);
427
+ return [2 /*return*/];
428
+ }
429
+ });
430
+ }); });
431
+ (0, bun_test_1.it)("query with a space", function () { return __awaiter(void 0, void 0, void 0, function () {
432
+ var greenBeans, res;
433
+ return __generator(this, function (_a) {
434
+ switch (_a.label) {
435
+ case 0: return [4 /*yield*/, tests_1.FoodModel.create({
436
+ calories: 102,
437
+ created: Date.now() - 10,
438
+ name: "Green Beans",
439
+ ownerId: admin === null || admin === void 0 ? void 0 : admin._id,
440
+ })];
441
+ case 1:
442
+ greenBeans = _a.sent();
443
+ return [4 /*yield*/, agent.get("/food?".concat(qs_1.default.stringify({ name: "Green Beans" }))).expect(200)];
444
+ case 2:
445
+ res = _a.sent();
446
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
447
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(greenBeans === null || greenBeans === void 0 ? void 0 : greenBeans.id);
448
+ (0, bun_test_1.expect)(res.body.data[0].name).toBe("Green Beans");
449
+ return [2 /*return*/];
450
+ }
451
+ });
452
+ }); });
453
+ (0, bun_test_1.it)("query with a regex", function () { return __awaiter(void 0, void 0, void 0, function () {
454
+ var greenBeans, res;
455
+ return __generator(this, function (_a) {
456
+ switch (_a.label) {
457
+ case 0: return [4 /*yield*/, tests_1.FoodModel.create({
458
+ calories: 102,
459
+ created: Date.now() - 10,
460
+ name: "Green Beans",
461
+ ownerId: admin === null || admin === void 0 ? void 0 : admin._id,
462
+ })];
463
+ case 1:
464
+ greenBeans = _a.sent();
465
+ return [4 /*yield*/, agent.get("/food?".concat(qs_1.default.stringify({ name: { $regex: "Green" } }))).expect(200)];
466
+ case 2:
467
+ res = _a.sent();
468
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
469
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(greenBeans === null || greenBeans === void 0 ? void 0 : greenBeans.id);
470
+ (0, bun_test_1.expect)(res.body.data[0].name).toBe("Green Beans");
471
+ return [4 /*yield*/, agent.get("/food?".concat(qs_1.default.stringify({ name: { $regex: "green" } }))).expect(200)];
472
+ case 3:
473
+ res = _a.sent();
474
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(0);
475
+ return [4 /*yield*/, agent
476
+ .get("/food?".concat(qs_1.default.stringify({ name: { $options: "i", $regex: "green" } })))
477
+ .expect(200)];
478
+ case 4:
479
+ res = _a.sent();
480
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
481
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(greenBeans === null || greenBeans === void 0 ? void 0 : greenBeans.id);
482
+ return [2 /*return*/];
483
+ }
484
+ });
485
+ }); });
486
+ (0, bun_test_1.it)("query with an $in operator", function () { return __awaiter(void 0, void 0, void 0, function () {
487
+ var res, names1, names2;
488
+ return __generator(this, function (_a) {
489
+ switch (_a.label) {
490
+ case 0: return [4 /*yield*/, server
491
+ .get("/food?".concat(qs_1.default.stringify({
492
+ name: {
493
+ $in: ["Apple", "Spinach"],
494
+ },
495
+ })))
496
+ .expect(200)];
497
+ case 1:
498
+ res = _a.sent();
499
+ names1 = res.body.data.map(function (d) { return d.name; });
500
+ (0, bun_test_1.expect)(names1).toEqual(bun_test_1.expect.arrayContaining(["Spinach"]));
501
+ (0, bun_test_1.expect)(names1).toHaveLength(1);
502
+ return [4 /*yield*/, server
503
+ .get("/food?".concat(qs_1.default.stringify({
504
+ name: {
505
+ $in: ["Carrots", "Spinach"],
506
+ },
507
+ })))
508
+ .expect(200)];
509
+ case 2:
510
+ res = _a.sent();
511
+ names2 = res.body.data.map(function (d) { return d.name; });
512
+ (0, bun_test_1.expect)(names2).toEqual(bun_test_1.expect.arrayContaining(["Spinach", "Carrots"]));
513
+ (0, bun_test_1.expect)(names2).toHaveLength(2);
514
+ return [2 /*return*/];
515
+ }
516
+ });
517
+ }); });
518
+ (0, bun_test_1.it)("query with an $in for _ids in nested object", function () { return __awaiter(void 0, void 0, void 0, function () {
519
+ var res, names3;
520
+ return __generator(this, function (_a) {
521
+ switch (_a.label) {
522
+ case 0: return [4 /*yield*/, server
523
+ .get("/food?".concat(qs_1.default.stringify({
524
+ eatenBy: {
525
+ $in: [notAdmin._id.toString(), adminOther._id.toString()],
526
+ },
527
+ })))
528
+ .expect(200)];
529
+ case 1:
530
+ res = _a.sent();
531
+ (0, bun_test_1.expect)(res.body.more).toBe(false);
532
+ (0, bun_test_1.expect)(res.body.total).toBe(2);
533
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(2);
534
+ names3 = res.body.data.map(function (d) { return d.name; });
535
+ (0, bun_test_1.expect)(names3).toEqual(bun_test_1.expect.arrayContaining(["Carrots", "Pizza"]));
536
+ (0, bun_test_1.expect)(names3).toHaveLength(2);
537
+ return [2 /*return*/];
538
+ }
539
+ });
540
+ }); });
541
+ (0, bun_test_1.it)("query $and operator on same field", function () { return __awaiter(void 0, void 0, void 0, function () {
542
+ var res;
543
+ return __generator(this, function (_a) {
544
+ switch (_a.label) {
545
+ case 0: return [4 /*yield*/, agent
546
+ .get("/food?".concat(qs_1.default.stringify({ $and: [{ tags: "healthy" }, { tags: "cheap" }] })))
547
+ .expect(200)];
548
+ case 1:
549
+ res = _a.sent();
550
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
551
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(carrots === null || carrots === void 0 ? void 0 : carrots._id.toString());
552
+ return [2 /*return*/];
553
+ }
554
+ });
555
+ }); });
556
+ (0, bun_test_1.it)("query $and operator on same field, nested objects", function () { return __awaiter(void 0, void 0, void 0, function () {
557
+ var res;
558
+ return __generator(this, function (_a) {
559
+ switch (_a.label) {
560
+ case 0: return [4 /*yield*/, agent
561
+ .get("/food?".concat(qs_1.default.stringify({
562
+ $and: [{ eatenBy: admin.id }, { eatenBy: notAdmin.id }],
563
+ })))
564
+ .expect(200)];
565
+ case 1:
566
+ res = _a.sent();
567
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
568
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(carrots === null || carrots === void 0 ? void 0 : carrots._id.toString());
569
+ return [2 /*return*/];
570
+ }
571
+ });
572
+ }); });
573
+ (0, bun_test_1.it)("query $or operator on same field", function () { return __awaiter(void 0, void 0, void 0, function () {
574
+ var res, ids1;
575
+ return __generator(this, function (_a) {
576
+ switch (_a.label) {
577
+ case 0: return [4 /*yield*/, agent
578
+ .get("/food?".concat(qs_1.default.stringify({ $or: [{ name: "Carrots" }, { name: "Pizza" }] })))
579
+ .expect(200)];
580
+ case 1:
581
+ res = _a.sent();
582
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(2);
583
+ ids1 = res.body.data.map(function (d) { return d.id; });
584
+ (0, bun_test_1.expect)(ids1).toEqual(bun_test_1.expect.arrayContaining([carrots === null || carrots === void 0 ? void 0 : carrots._id.toString(), pizza === null || pizza === void 0 ? void 0 : pizza._id.toString()]));
585
+ (0, bun_test_1.expect)(ids1).toHaveLength(2);
586
+ return [2 /*return*/];
587
+ }
588
+ });
589
+ }); });
590
+ (0, bun_test_1.it)("query $and operator on same field, nested objects for $or", function () { return __awaiter(void 0, void 0, void 0, function () {
591
+ var res, ids2;
592
+ return __generator(this, function (_a) {
593
+ switch (_a.label) {
594
+ case 0: return [4 /*yield*/, agent
595
+ .get("/food?".concat(qs_1.default.stringify({
596
+ $or: [{ eatenBy: admin.id }, { eatenBy: notAdmin.id }],
597
+ limit: 3,
598
+ })))
599
+ .expect(200)];
600
+ case 1:
601
+ res = _a.sent();
602
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(2);
603
+ ids2 = res.body.data.map(function (d) { return d.id; });
604
+ (0, bun_test_1.expect)(ids2).toEqual(bun_test_1.expect.arrayContaining([carrots === null || carrots === void 0 ? void 0 : carrots._id.toString(), spinach === null || spinach === void 0 ? void 0 : spinach._id.toString()]));
605
+ (0, bun_test_1.expect)(ids2).toHaveLength(2);
606
+ return [2 /*return*/];
607
+ }
608
+ });
609
+ }); });
610
+ (0, bun_test_1.it)("query $and and $or are rejected if field is not in queryFields", function () { return __awaiter(void 0, void 0, void 0, function () {
611
+ var res;
612
+ return __generator(this, function (_a) {
613
+ switch (_a.label) {
614
+ case 0: return [4 /*yield*/, agent
615
+ .get("/food?".concat(qs_1.default.stringify({ $and: [{ ownerId: "healthy" }, { tags: "cheap" }] })))
616
+ .expect(400)];
617
+ case 1:
618
+ res = _a.sent();
619
+ (0, bun_test_1.expect)(res.body.title).toBe("ownerId is not allowed as a query param.");
620
+ return [4 /*yield*/, agent
621
+ .get("/food?".concat(qs_1.default.stringify({ $and: [{ tags: "cheap" }, { ownerId: "healthy" }] })))
622
+ .expect(400)];
623
+ case 2:
624
+ res = _a.sent();
625
+ (0, bun_test_1.expect)(res.body.title).toBe("ownerId is not allowed as a query param.");
626
+ return [4 /*yield*/, agent
627
+ .get("/food?".concat(qs_1.default.stringify({ $or: [{ tags: "cheap" }, { ownerId: "healthy" }] })))
628
+ .expect(400)];
629
+ case 3:
630
+ res = _a.sent();
631
+ (0, bun_test_1.expect)(res.body.title).toBe("ownerId is not allowed as a query param.");
632
+ return [2 /*return*/];
633
+ }
634
+ });
635
+ }); });
636
+ (0, bun_test_1.it)("query with a number", function () { return __awaiter(void 0, void 0, void 0, function () {
637
+ var res;
638
+ return __generator(this, function (_a) {
639
+ switch (_a.label) {
640
+ case 0: return [4 /*yield*/, agent.get("/food?calories=100").expect(200)];
641
+ case 1:
642
+ res = _a.sent();
643
+ (0, bun_test_1.expect)(res.body.data).toHaveLength(1);
644
+ (0, bun_test_1.expect)(res.body.data[0].id).toBe(carrots === null || carrots === void 0 ? void 0 : carrots._id.toString());
645
+ return [2 /*return*/];
646
+ }
647
+ });
648
+ }); });
649
+ (0, bun_test_1.it)("update", function () { return __awaiter(void 0, void 0, void 0, function () {
650
+ var res;
651
+ return __generator(this, function (_a) {
652
+ switch (_a.label) {
653
+ case 0: return [4 /*yield*/, agent.patch("/food/".concat(spinach._id)).send({ name: "Kale" }).expect(200)];
654
+ case 1:
655
+ res = _a.sent();
656
+ (0, bun_test_1.expect)(res.body.data.name).toBe("Kale");
657
+ (0, bun_test_1.expect)(res.body.data.calories).toBe(1);
658
+ (0, bun_test_1.expect)(res.body.data.hidden).toBe(false);
659
+ return [4 /*yield*/, agent
660
+ .patch("/food/".concat(spinach._id))
661
+ .send({ lastEatenWith: { dressing: "2023-12-03T00:00:20.000Z" } })
662
+ .expect(200)];
663
+ case 2:
664
+ res = _a.sent();
665
+ (0, bun_test_1.expect)(res.body.data.name).toBe("Kale");
666
+ (0, bun_test_1.expect)(res.body.data.calories).toBe(1);
667
+ (0, bun_test_1.expect)(res.body.data.hidden).toBe(false);
668
+ (0, bun_test_1.expect)(res.body.data.lastEatenWith).toEqual({
669
+ dressing: "2023-12-03T00:00:20.000Z",
670
+ });
671
+ return [4 /*yield*/, agent
672
+ .patch("/food/".concat(spinach._id))
673
+ .send({
674
+ lastEatenWith: {
675
+ cucumber: "2023-12-04T12:00:20.000Z",
676
+ dressing: "2023-12-03T00:00:20.000Z",
677
+ },
678
+ })
679
+ .expect(200)];
680
+ case 3:
681
+ res = _a.sent();
682
+ (0, bun_test_1.expect)(res.body.data.lastEatenWith).toEqual({
683
+ cucumber: "2023-12-04T12:00:20.000Z",
684
+ dressing: "2023-12-03T00:00:20.000Z",
685
+ });
686
+ return [2 /*return*/];
687
+ }
688
+ });
689
+ }); });
690
+ (0, bun_test_1.it)("update using dot notation", function () { return __awaiter(void 0, void 0, void 0, function () {
691
+ var res, dbSpinach;
692
+ return __generator(this, function (_a) {
693
+ switch (_a.label) {
694
+ case 0: return [4 /*yield*/, agent
695
+ .patch("/food/".concat(spinach._id))
696
+ .send({ "source.href": "https://food.com" })
697
+ .expect(200)];
698
+ case 1:
699
+ res = _a.sent();
700
+ (0, bun_test_1.expect)(res.body.data.source.href).toBe("https://food.com");
701
+ (0, bun_test_1.expect)(res.body.data.source.name).toBe("Brand");
702
+ (0, bun_test_1.expect)(res.body.data.source.dateAdded).toBe("2023-12-13T12:30:00.000Z");
703
+ return [4 /*yield*/, tests_1.FoodModel.findById(spinach._id)];
704
+ case 2:
705
+ dbSpinach = _a.sent();
706
+ (0, bun_test_1.expect)(dbSpinach === null || dbSpinach === void 0 ? void 0 : dbSpinach.source.href).toBe("https://food.com");
707
+ (0, bun_test_1.expect)(dbSpinach === null || dbSpinach === void 0 ? void 0 : dbSpinach.source.name).toBe("Brand");
708
+ (0, bun_test_1.expect)(dbSpinach === null || dbSpinach === void 0 ? void 0 : dbSpinach.source.dateAdded).toBe("2023-12-13T12:30:00.000Z");
709
+ return [2 /*return*/];
710
+ }
711
+ });
712
+ }); });
713
+ });
714
+ (0, bun_test_1.describe)("special query params", function () {
715
+ var server;
716
+ var app;
717
+ var admin;
718
+ (0, bun_test_1.beforeEach)(function () { return __awaiter(void 0, void 0, void 0, function () {
719
+ var _a;
720
+ return __generator(this, function (_b) {
721
+ switch (_b.label) {
722
+ case 0: return [4 /*yield*/, (0, tests_1.setupDb)()];
723
+ case 1:
724
+ _a = __read.apply(void 0, [_b.sent(), 1]), admin = _a[0];
725
+ return [4 /*yield*/, tests_1.FoodModel.create({
726
+ calories: 1,
727
+ created: new Date("2021-12-03T00:00:20.000Z"),
728
+ hidden: false,
729
+ name: "Spinach",
730
+ ownerId: admin._id,
731
+ })];
732
+ case 2:
733
+ _b.sent();
734
+ app = (0, tests_1.getBaseServer)();
735
+ (0, auth_1.setupAuth)(app, tests_1.UserModel);
736
+ (0, auth_1.addAuthRoutes)(app, tests_1.UserModel);
737
+ return [2 /*return*/];
738
+ }
739
+ });
740
+ }); });
741
+ (0, bun_test_1.it)("period query param is stripped from query", function () { return __awaiter(void 0, void 0, void 0, function () {
742
+ var res;
743
+ return __generator(this, function (_a) {
744
+ switch (_a.label) {
745
+ case 0:
746
+ app.use("/food", (0, api_1.modelRouter)(tests_1.FoodModel, {
747
+ allowAnonymous: true,
748
+ permissions: {
749
+ create: [permissions_1.Permissions.IsAny],
750
+ delete: [permissions_1.Permissions.IsAny],
751
+ list: [permissions_1.Permissions.IsAny],
752
+ read: [permissions_1.Permissions.IsAny],
753
+ update: [permissions_1.Permissions.IsAny],
754
+ },
755
+ queryFields: ["name", "period"],
756
+ queryFilter: function (_user, query) {
757
+ if (query === null || query === void 0 ? void 0 : query.period) {
758
+ return query;
759
+ }
760
+ return query !== null && query !== void 0 ? query : {};
761
+ },
762
+ }));
763
+ server = (0, supertest_1.default)(app);
764
+ return [4 /*yield*/, server.get("/food?period=weekly").expect(200)];
765
+ case 1:
766
+ res = _a.sent();
767
+ (0, bun_test_1.expect)(res.body.data).toBeDefined();
768
+ return [2 /*return*/];
769
+ }
770
+ });
771
+ }); });
772
+ (0, bun_test_1.it)("query with false value", function () { return __awaiter(void 0, void 0, void 0, function () {
773
+ var res;
774
+ return __generator(this, function (_a) {
775
+ switch (_a.label) {
776
+ case 0: return [4 /*yield*/, tests_1.FoodModel.create({
777
+ calories: 50,
778
+ created: new Date("2021-12-04T00:00:20.000Z"),
779
+ hidden: true,
780
+ name: "HiddenFood",
781
+ ownerId: admin._id,
782
+ })];
783
+ case 1:
784
+ _a.sent();
785
+ app.use("/food", (0, api_1.modelRouter)(tests_1.FoodModel, {
786
+ allowAnonymous: true,
787
+ permissions: {
788
+ create: [permissions_1.Permissions.IsAny],
789
+ delete: [permissions_1.Permissions.IsAny],
790
+ list: [permissions_1.Permissions.IsAny],
791
+ read: [permissions_1.Permissions.IsAny],
792
+ update: [permissions_1.Permissions.IsAny],
793
+ },
794
+ queryFields: ["name", "hidden"],
795
+ }));
796
+ server = (0, supertest_1.default)(app);
797
+ return [4 /*yield*/, server.get("/food?hidden=false").expect(200)];
798
+ case 2:
799
+ res = _a.sent();
800
+ (0, bun_test_1.expect)(res.body.data.every(function (f) { return f.hidden === false; })).toBe(true);
801
+ return [2 /*return*/];
802
+ }
803
+ });
804
+ }); });
805
+ });