@casekit/orm2 0.0.0-20250331202540 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/build/builders/buildCount.d.ts +2 -1
  2. package/build/builders/buildCount.js +5 -8
  3. package/build/builders/buildCount.test.js +5 -5
  4. package/build/builders/buildCreate.d.ts +2 -1
  5. package/build/builders/buildCreate.js +6 -3
  6. package/build/builders/buildCreate.test.js +4 -4
  7. package/build/builders/buildDelete.d.ts +2 -1
  8. package/build/builders/buildDelete.js +2 -2
  9. package/build/builders/buildDelete.test.js +8 -8
  10. package/build/builders/buildFind.d.ts +2 -1
  11. package/build/builders/buildFind.js +5 -8
  12. package/build/builders/buildFind.test.js +4 -4
  13. package/build/builders/buildUpdate.d.ts +2 -1
  14. package/build/builders/buildUpdate.js +6 -3
  15. package/build/builders/buildUpdate.test.js +8 -8
  16. package/build/builders/buildWhere.d.ts +2 -1
  17. package/build/builders/buildWhere.js +30 -8
  18. package/build/builders/buildWhere.test.js +39 -24
  19. package/build/connection.d.ts +2 -2
  20. package/build/index.d.ts +1 -1
  21. package/build/index.js +1 -1
  22. package/build/orm.count.d.ts +2 -10
  23. package/build/orm.count.js +2 -11
  24. package/build/orm.createMany.d.ts +2 -1
  25. package/build/orm.createMany.js +2 -2
  26. package/build/orm.createOne.d.ts +2 -1
  27. package/build/orm.createOne.js +2 -2
  28. package/build/orm.d.ts +3 -3
  29. package/build/orm.deleteMany.d.ts +2 -1
  30. package/build/orm.deleteMany.js +2 -2
  31. package/build/orm.deleteOne.d.ts +2 -1
  32. package/build/orm.deleteOne.js +2 -2
  33. package/build/orm.findMany.d.ts +2 -1
  34. package/build/orm.findMany.js +3 -3
  35. package/build/orm.findOne.d.ts +2 -1
  36. package/build/orm.findOne.js +11 -19
  37. package/build/orm.js +13 -13
  38. package/build/orm.restrict.d.ts +2 -1
  39. package/build/orm.restrict.js +2 -2
  40. package/build/orm.updateMany.d.ts +2 -1
  41. package/build/orm.updateMany.js +3 -3
  42. package/build/orm.updateOne.d.ts +2 -1
  43. package/build/orm.updateOne.js +2 -2
  44. package/build/tests/orm.findMany.includeManyToOne.test.js +21 -5
  45. package/build/tests/orm.findOne.includeManyToMany.test.js +270 -0
  46. package/build/tests/orm.findOne.includeManyToOne.test.js +280 -0
  47. package/build/tests/orm.findOne.includeOneToMany.test.js +454 -0
  48. package/build/tests/orm.findOne.select.test.js +205 -0
  49. package/build/tests/orm.findOne.where.test.js +471 -0
  50. package/build/tests/orm.middleware.findOne.test.d.ts +1 -0
  51. package/build/tests/orm.middleware.set.test.d.ts +1 -0
  52. package/build/tests/orm.middleware.set.test.js +100 -0
  53. package/build/tests/orm.middleware.updateMany.test.d.ts +1 -0
  54. package/build/tests/orm.middleware.updateOne.test.d.ts +1 -0
  55. package/build/tests/orm.middleware.values.test.d.ts +1 -0
  56. package/build/tests/orm.middleware.values.test.js +126 -0
  57. package/build/tests/orm.middleware.where.test.d.ts +1 -0
  58. package/build/tests/orm.middleware.where.test.js +1054 -0
  59. package/build/tests/util/db.d.ts +53 -71
  60. package/build/types/CreateOneResult.d.ts +6 -2
  61. package/build/types/CreateOneResult.test-d.js +3 -0
  62. package/build/types/Middleware.d.ts +14 -0
  63. package/build/types/Middleware.js +37 -1
  64. package/build/types/WhereClause.d.ts +8 -8
  65. package/build/util/applySetMiddleware.d.ts +5 -0
  66. package/build/util/applySetMiddleware.js +7 -0
  67. package/build/util/applyValuesMiddleware.d.ts +5 -0
  68. package/build/util/applyValuesMiddleware.js +7 -0
  69. package/build/util/applyWhereMiddleware.d.ts +5 -0
  70. package/build/util/applyWhereMiddleware.js +7 -0
  71. package/build/util/applyWhereMiddleware.test.d.ts +1 -0
  72. package/build/util/applyWhereMiddleware.test.js +88 -0
  73. package/build/util/resultSchema.d.ts +6 -6
  74. package/package.json +23 -24
  75. /package/build/tests/{orm.count.middleware.test.d.ts → orm.findOne.includeManyToMany.test.d.ts} +0 -0
  76. /package/build/tests/{orm.createMany.middleware.test.d.ts → orm.findOne.includeManyToOne.test.d.ts} +0 -0
  77. /package/build/tests/{orm.createOne.middleware.test.d.ts → orm.findOne.includeOneToMany.test.d.ts} +0 -0
  78. /package/build/tests/{orm.deleteMany.middleware.test.d.ts → orm.findOne.select.test.d.ts} +0 -0
  79. /package/build/tests/{orm.deleteOne.middleware.test.d.ts → orm.findOne.where.test.d.ts} +0 -0
  80. /package/build/tests/{orm.findMany.middleware.test.d.ts → orm.middleware.count.test.d.ts} +0 -0
  81. /package/build/tests/{orm.count.middleware.test.js → orm.middleware.count.test.js} +0 -0
  82. /package/build/tests/{orm.findOne.middleware.test.d.ts → orm.middleware.createMany.test.d.ts} +0 -0
  83. /package/build/tests/{orm.createMany.middleware.test.js → orm.middleware.createMany.test.js} +0 -0
  84. /package/build/tests/{orm.updateMany.middleware.test.d.ts → orm.middleware.createOne.test.d.ts} +0 -0
  85. /package/build/tests/{orm.createOne.middleware.test.js → orm.middleware.createOne.test.js} +0 -0
  86. /package/build/tests/{orm.updateOne.middleware.test.d.ts → orm.middleware.deleteMany.test.d.ts} +0 -0
  87. /package/build/tests/{orm.deleteMany.middleware.test.js → orm.middleware.deleteMany.test.js} +0 -0
  88. /package/build/{types/BaseFindParams.d.ts → tests/orm.middleware.deleteOne.test.d.ts} +0 -0
  89. /package/build/tests/{orm.deleteOne.middleware.test.js → orm.middleware.deleteOne.test.js} +0 -0
  90. /package/build/{types/BaseFindParams.js → tests/orm.middleware.findMany.test.d.ts} +0 -0
  91. /package/build/tests/{orm.findMany.middleware.test.js → orm.middleware.findMany.test.js} +0 -0
  92. /package/build/tests/{orm.findOne.middleware.test.js → orm.middleware.findOne.test.js} +0 -0
  93. /package/build/tests/{orm.updateMany.middleware.test.js → orm.middleware.updateMany.test.js} +0 -0
  94. /package/build/tests/{orm.updateOne.middleware.test.js → orm.middleware.updateOne.test.js} +0 -0
@@ -0,0 +1,454 @@
1
+ import { afterAll, beforeAll, beforeEach, describe, expect, test, } from "vitest";
2
+ import { $not } from "../operators.js";
3
+ import { createTestDB } from "./util/db.js";
4
+ describe("findOne: include oneToMany", () => {
5
+ const { db, logger, factory } = createTestDB();
6
+ beforeEach(() => {
7
+ logger.clear();
8
+ });
9
+ beforeAll(async () => {
10
+ await db.connect();
11
+ });
12
+ afterAll(async () => {
13
+ await db.close();
14
+ });
15
+ test("can include oneToMany relations", async () => {
16
+ await db.transact(async (db) => {
17
+ await db.createOne("user", {
18
+ values: factory.user({ id: 1, name: "User 1" }),
19
+ returning: ["id"],
20
+ });
21
+ await db.createMany("post", {
22
+ values: [
23
+ factory.post({
24
+ id: 1,
25
+ authorId: 1,
26
+ title: "Post 1",
27
+ }),
28
+ factory.post({
29
+ id: 2,
30
+ authorId: 1,
31
+ title: "Post 2",
32
+ }),
33
+ ],
34
+ });
35
+ const user = await db.findOne("user", {
36
+ select: ["id", "name"],
37
+ where: { id: 1 },
38
+ include: {
39
+ posts: {
40
+ select: ["id", "title"],
41
+ orderBy: ["id"],
42
+ },
43
+ },
44
+ });
45
+ expect(user).toEqual({
46
+ id: 1,
47
+ name: "User 1",
48
+ posts: [
49
+ { id: 1, title: "Post 1" },
50
+ { id: 2, title: "Post 2" },
51
+ ],
52
+ });
53
+ }, { rollback: true });
54
+ });
55
+ test("can filter included oneToMany relations", async () => {
56
+ await db.transact(async (db) => {
57
+ await db.createOne("user", {
58
+ values: factory.user({ id: 1 }),
59
+ returning: ["id"],
60
+ });
61
+ await db.createMany("post", {
62
+ values: [
63
+ factory.post({
64
+ id: 1,
65
+ authorId: 1,
66
+ publishedAt: new Date("2024-01-01"),
67
+ }),
68
+ factory.post({
69
+ id: 2,
70
+ authorId: 1,
71
+ publishedAt: null,
72
+ }),
73
+ factory.post({
74
+ id: 3,
75
+ authorId: 1,
76
+ publishedAt: new Date("2024-01-02"),
77
+ }),
78
+ ],
79
+ });
80
+ const user = await db.findOne("user", {
81
+ select: ["id"],
82
+ where: { id: 1 },
83
+ include: {
84
+ posts: {
85
+ select: ["id", "publishedAt"],
86
+ where: {
87
+ publishedAt: { [$not]: null },
88
+ },
89
+ orderBy: ["id"],
90
+ },
91
+ },
92
+ });
93
+ expect(user).toEqual({
94
+ id: 1,
95
+ posts: [
96
+ { id: 1, publishedAt: new Date("2024-01-01") },
97
+ { id: 3, publishedAt: new Date("2024-01-02") },
98
+ ],
99
+ });
100
+ }, { rollback: true });
101
+ });
102
+ test("can order included oneToMany relations", async () => {
103
+ await db.transact(async (db) => {
104
+ await db.createOne("user", {
105
+ values: factory.user({ id: 1 }),
106
+ returning: ["id"],
107
+ });
108
+ // Create posts with different creation dates
109
+ await db.createMany("post", {
110
+ values: [
111
+ factory.post({
112
+ id: 1,
113
+ authorId: 1,
114
+ createdAt: new Date("2024-01-01"),
115
+ }),
116
+ factory.post({
117
+ id: 2,
118
+ authorId: 1,
119
+ createdAt: new Date("2024-01-03"),
120
+ }),
121
+ factory.post({
122
+ id: 3,
123
+ authorId: 1,
124
+ createdAt: new Date("2024-01-02"),
125
+ }),
126
+ ],
127
+ });
128
+ const user = await db.findOne("user", {
129
+ select: ["id"],
130
+ where: { id: 1 },
131
+ include: {
132
+ posts: {
133
+ select: ["id", "createdAt"],
134
+ orderBy: [["createdAt", "desc"]],
135
+ },
136
+ },
137
+ });
138
+ expect(user).toEqual({
139
+ id: 1,
140
+ posts: [
141
+ { id: 2, createdAt: new Date("2024-01-03") },
142
+ { id: 3, createdAt: new Date("2024-01-02") },
143
+ { id: 1, createdAt: new Date("2024-01-01") },
144
+ ],
145
+ });
146
+ }, { rollback: true });
147
+ });
148
+ test("can limit and offset included oneToMany relations", async () => {
149
+ await db.transact(async (db) => {
150
+ await db.createOne("user", {
151
+ values: factory.user({ id: 1 }),
152
+ returning: ["id"],
153
+ });
154
+ // Create multiple posts
155
+ await db.createMany("post", {
156
+ values: [
157
+ factory.post({ id: 1, authorId: 1 }),
158
+ factory.post({ id: 2, authorId: 1 }),
159
+ factory.post({ id: 3, authorId: 1 }),
160
+ factory.post({ id: 4, authorId: 1 }),
161
+ ],
162
+ });
163
+ const user = await db.findOne("user", {
164
+ select: ["id"],
165
+ where: { id: 1 },
166
+ include: {
167
+ posts: {
168
+ select: ["id"],
169
+ orderBy: ["id"],
170
+ limit: 2,
171
+ offset: 1,
172
+ },
173
+ },
174
+ });
175
+ expect(user).toEqual({
176
+ id: 1,
177
+ posts: [{ id: 2 }, { id: 3 }],
178
+ });
179
+ }, { rollback: true });
180
+ });
181
+ test("can include nested relations in oneToMany relations", async () => {
182
+ await db.transact(async (db) => {
183
+ // Create user and colors first
184
+ await db.createOne("user", {
185
+ values: factory.user({ id: 1, name: "User 1" }),
186
+ returning: ["id"],
187
+ });
188
+ await db.createOne("user", {
189
+ values: factory.user({ id: 2, name: "User 2" }),
190
+ returning: ["id"],
191
+ });
192
+ await db.createMany("color", {
193
+ values: [
194
+ factory.color({ hex: "#FF0000", name: "Red" }),
195
+ factory.color({ hex: "#00FF00", name: "Green" }),
196
+ ],
197
+ });
198
+ // Create posts with N:1 relations to colors
199
+ await db.createMany("post", {
200
+ values: [
201
+ factory.post({
202
+ id: 1,
203
+ authorId: 1,
204
+ title: "Post 1",
205
+ backgroundColorValue: "#FF0000",
206
+ }),
207
+ factory.post({
208
+ id: 2,
209
+ authorId: 1,
210
+ title: "Post 2",
211
+ backgroundColorValue: "#00FF00",
212
+ }),
213
+ ],
214
+ });
215
+ // Create likes (N:N relation via post -> likes <- user)
216
+ await db.createMany("like", {
217
+ values: [
218
+ factory.like({ id: 1, userId: 2, postId: 1 }),
219
+ factory.like({ id: 2, userId: 2, postId: 2 }),
220
+ ],
221
+ });
222
+ const user = await db.findOne("user", {
223
+ select: ["id", "name"],
224
+ where: { id: 1 },
225
+ include: {
226
+ posts: {
227
+ select: ["id", "title"],
228
+ include: {
229
+ backgroundColor: {
230
+ select: ["hex", "name"],
231
+ },
232
+ likes: {
233
+ select: ["id"],
234
+ include: {
235
+ user: {
236
+ select: ["id", "name"],
237
+ },
238
+ },
239
+ },
240
+ },
241
+ orderBy: ["id"],
242
+ },
243
+ },
244
+ });
245
+ expect(user).toEqual({
246
+ id: 1,
247
+ name: "User 1",
248
+ posts: [
249
+ {
250
+ id: 1,
251
+ title: "Post 1",
252
+ backgroundColor: {
253
+ hex: "#FF0000",
254
+ name: "Red",
255
+ },
256
+ likes: [
257
+ {
258
+ id: 1,
259
+ user: { id: 2, name: "User 2" },
260
+ },
261
+ ],
262
+ },
263
+ {
264
+ id: 2,
265
+ title: "Post 2",
266
+ backgroundColor: {
267
+ hex: "#00FF00",
268
+ name: "Green",
269
+ },
270
+ likes: [
271
+ {
272
+ id: 2,
273
+ user: { id: 2, name: "User 2" },
274
+ },
275
+ ],
276
+ },
277
+ ],
278
+ });
279
+ }, { rollback: true });
280
+ });
281
+ test("can filter and order deeply nested relations", async () => {
282
+ await db.transact(async (db) => {
283
+ await db.createOne("user", {
284
+ values: factory.user({ id: 1 }),
285
+ returning: ["id"],
286
+ });
287
+ await db.createOne("user", {
288
+ values: factory.user({ id: 2 }),
289
+ returning: ["id"],
290
+ });
291
+ await db.createMany("color", {
292
+ values: [
293
+ factory.color({ hex: "#FF0000", name: "Red" }),
294
+ factory.color({ hex: "#00FF00", name: "Green" }),
295
+ ],
296
+ });
297
+ await db.createMany("post", {
298
+ values: [
299
+ factory.post({
300
+ id: 1,
301
+ authorId: 1,
302
+ backgroundColorValue: "#FF0000",
303
+ createdAt: new Date("2024-01-01"),
304
+ }),
305
+ factory.post({
306
+ id: 2,
307
+ authorId: 1,
308
+ backgroundColorValue: "#00FF00",
309
+ createdAt: new Date("2024-01-02"),
310
+ }),
311
+ ],
312
+ });
313
+ await db.createMany("like", {
314
+ values: [
315
+ factory.like({
316
+ id: 1,
317
+ userId: 2,
318
+ postId: 1,
319
+ createdAt: new Date("2024-01-03"),
320
+ }),
321
+ factory.like({
322
+ id: 2,
323
+ userId: 1,
324
+ postId: 1,
325
+ createdAt: new Date("2024-01-04"),
326
+ }),
327
+ factory.like({
328
+ id: 3,
329
+ userId: 2,
330
+ postId: 2,
331
+ createdAt: new Date("2024-01-04"),
332
+ }),
333
+ ],
334
+ });
335
+ const user = await db.findOne("user", {
336
+ select: ["id"],
337
+ where: { id: 1 },
338
+ include: {
339
+ posts: {
340
+ select: ["id"],
341
+ where: {},
342
+ include: {
343
+ backgroundColor: {
344
+ select: ["name"],
345
+ where: {
346
+ name: "Red",
347
+ },
348
+ },
349
+ likes: {
350
+ select: ["id", "createdAt"],
351
+ orderBy: [["createdAt", "desc"]],
352
+ include: {
353
+ user: {
354
+ select: ["id"],
355
+ },
356
+ },
357
+ },
358
+ },
359
+ },
360
+ },
361
+ });
362
+ expect(user).toEqual({
363
+ id: 1,
364
+ posts: [
365
+ {
366
+ id: 1,
367
+ backgroundColor: { name: "Red" },
368
+ likes: [
369
+ {
370
+ id: 2,
371
+ createdAt: new Date("2024-01-04"),
372
+ user: { id: 1 },
373
+ },
374
+ {
375
+ id: 1,
376
+ createdAt: new Date("2024-01-03"),
377
+ user: { id: 2 },
378
+ },
379
+ ],
380
+ },
381
+ ],
382
+ });
383
+ }, { rollback: true });
384
+ });
385
+ test("can include oneToMany relations with multi-field joins", async () => {
386
+ await db.transact(async (db) => {
387
+ await db.createMany("user", {
388
+ values: [
389
+ factory.user({ id: 1, name: "Lynne Tillman" }),
390
+ factory.user({ id: 2, name: "Stewart Home" }),
391
+ factory.user({ id: 3, name: "Judith Butler" }),
392
+ ],
393
+ });
394
+ await db.createMany("friendship", {
395
+ values: [
396
+ factory.friendship({ userId: 1, friendId: 2 }),
397
+ factory.friendship({ userId: 1, friendId: 3 }),
398
+ ],
399
+ });
400
+ await db.createMany("friendshipStats", {
401
+ values: [
402
+ factory.friendshipStats({
403
+ id: 1,
404
+ userId: 1,
405
+ friendId: 2,
406
+ messagesSent: 100,
407
+ likesGiven: 50,
408
+ }),
409
+ factory.friendshipStats({
410
+ id: 2,
411
+ userId: 1,
412
+ friendId: 3,
413
+ messagesSent: 200,
414
+ likesGiven: 75,
415
+ }),
416
+ ],
417
+ });
418
+ const user = await db.findOne("user", {
419
+ select: ["id"],
420
+ where: { id: 1 },
421
+ include: {
422
+ friendships: {
423
+ select: ["userId", "friendId"],
424
+ include: {
425
+ friend: {
426
+ select: ["id", "name"],
427
+ },
428
+ stats: {
429
+ select: ["messagesSent", "likesGiven"],
430
+ },
431
+ },
432
+ },
433
+ },
434
+ });
435
+ expect(user).toEqual({
436
+ id: 1,
437
+ friendships: [
438
+ {
439
+ userId: 1,
440
+ friendId: 2,
441
+ friend: { id: 2, name: "Stewart Home" },
442
+ stats: { messagesSent: 100, likesGiven: 50 },
443
+ },
444
+ {
445
+ userId: 1,
446
+ friendId: 3,
447
+ friend: { id: 3, name: "Judith Butler" },
448
+ stats: { messagesSent: 200, likesGiven: 75 },
449
+ },
450
+ ],
451
+ });
452
+ }, { rollback: true });
453
+ });
454
+ });
@@ -0,0 +1,205 @@
1
+ import { afterAll, beforeAll, beforeEach, describe, expect, test, } from "vitest";
2
+ import { createTestDB } from "./util/db.js";
3
+ describe("findOne: select", () => {
4
+ const { db, logger, factory } = createTestDB();
5
+ beforeEach(() => {
6
+ logger.clear();
7
+ });
8
+ beforeAll(async () => {
9
+ await db.connect();
10
+ });
11
+ afterAll(async () => {
12
+ await db.close();
13
+ });
14
+ test("selected fields are returned", async () => {
15
+ await db.transact(async (db) => {
16
+ await db.createOne("user", {
17
+ values: factory.user({ id: 1, name: "Lynne Tillman" }),
18
+ });
19
+ const user = await db.findOne("user", {
20
+ select: ["id", "name"],
21
+ where: { id: 1 },
22
+ });
23
+ expect(user).toEqual({ id: 1, name: "Lynne Tillman" });
24
+ }, { rollback: true });
25
+ });
26
+ test("primary key will not be returned if it is not selected", async () => {
27
+ await db.transact(async (db) => {
28
+ await db.createOne("user", {
29
+ values: factory.user({ id: 1, name: "Lynne Tillman" }),
30
+ });
31
+ const selectedUser = await db.findOne("user", {
32
+ select: ["name"],
33
+ where: { id: 1 },
34
+ });
35
+ expect(selectedUser).toEqual({ name: "Lynne Tillman" });
36
+ }, { rollback: true });
37
+ });
38
+ test("enum fields can be selected", async () => {
39
+ await db.transact(async (db) => {
40
+ await db.createOne("user", {
41
+ values: factory.user({ id: 1, role: "admin" }),
42
+ });
43
+ const user = await db.findOne("user", {
44
+ select: ["id", "role"],
45
+ where: { id: 1 },
46
+ });
47
+ expect(user).toEqual({ id: 1, role: "admin" });
48
+ }, { rollback: true });
49
+ });
50
+ test("array fields can be selected", async () => {
51
+ await db.transact(async (db) => {
52
+ await db.createOne("user", {
53
+ values: factory.user({ id: 1, role: "user" }),
54
+ });
55
+ await db.createOne("post", {
56
+ values: factory.post({
57
+ id: 3,
58
+ tags: ["foo", "bar"],
59
+ authorId: 1,
60
+ }),
61
+ });
62
+ const post = await db.findOne("post", {
63
+ select: ["id", "tags"],
64
+ where: { id: 3 },
65
+ });
66
+ expect(post).toEqual({ id: 3, tags: ["foo", "bar"] });
67
+ }, { rollback: true });
68
+ });
69
+ test("json fields can be selected", async () => {
70
+ await db.transact(async (db) => {
71
+ await db.createOne("user", {
72
+ values: factory.user({ id: 1, role: "user" }),
73
+ });
74
+ await db.createOne("post", {
75
+ values: factory.post({
76
+ id: 3,
77
+ authorId: 1,
78
+ metadata: {
79
+ foo: "a",
80
+ bar: [
81
+ { baz: "good", quux: true },
82
+ { baz: "bad", quux: false },
83
+ ],
84
+ },
85
+ }),
86
+ });
87
+ const post = await db.findOne("post", {
88
+ select: ["metadata"],
89
+ where: { id: 3 },
90
+ });
91
+ expect(post).toEqual({
92
+ metadata: {
93
+ foo: "a",
94
+ bar: [
95
+ { baz: "good", quux: true },
96
+ { baz: "bad", quux: false },
97
+ ],
98
+ },
99
+ });
100
+ }, { rollback: true });
101
+ });
102
+ test("throws error when no records match criteria", async () => {
103
+ await db.transact(async (db) => {
104
+ await expect(db.findOne("user", {
105
+ select: ["id", "name"],
106
+ where: { id: 999 },
107
+ })).rejects.toThrow("Expected one row, but found none");
108
+ }, { rollback: true });
109
+ });
110
+ test("handles null values in selected fields correctly", async () => {
111
+ await db.transact(async (db) => {
112
+ await db.createOne("user", {
113
+ values: factory.user({
114
+ id: 1,
115
+ deletedAt: null,
116
+ }),
117
+ });
118
+ const user = await db.findOne("user", {
119
+ select: ["id", "deletedAt"],
120
+ where: { id: 1 },
121
+ });
122
+ expect(user).toEqual({
123
+ id: 1,
124
+ deletedAt: null,
125
+ });
126
+ }, { rollback: true });
127
+ });
128
+ test("can select all available fields", async () => {
129
+ await db.transact(async (db) => {
130
+ const userData = factory.user({
131
+ id: 1,
132
+ name: "Test User",
133
+ email: "test@example.com",
134
+ role: "user",
135
+ preferences: { theme: "dark" },
136
+ createdAt: new Date("2024-01-01"),
137
+ deletedAt: null,
138
+ });
139
+ await db.createOne("user", { values: userData });
140
+ const user = await db.findOne("user", {
141
+ select: [
142
+ "id",
143
+ "name",
144
+ "email",
145
+ "role",
146
+ "preferences",
147
+ "createdAt",
148
+ "deletedAt",
149
+ ],
150
+ where: { id: 1 },
151
+ });
152
+ expect(user).toEqual(userData);
153
+ }, { rollback: true });
154
+ });
155
+ test("throws error when selecting from non-existent model", async () => {
156
+ await db.transact(async (db) => {
157
+ await expect(
158
+ // @ts-expect-error - Testing runtime behavior
159
+ db.findOne("invalid", {
160
+ select: ["id"],
161
+ where: { id: 1 },
162
+ })).rejects.toThrow(`Model "invalid" not found`);
163
+ }, { rollback: true });
164
+ });
165
+ test("throws error when selecting non-existent field", async () => {
166
+ await db.transact(async (db) => {
167
+ await expect(db.findOne("user", {
168
+ // @ts-expect-error - Testing runtime behavior
169
+ select: ["id", "nonexistentField"],
170
+ where: { id: 1 },
171
+ })).rejects.toThrow(`Field "nonexistentField" not found in model "user"`);
172
+ }, { rollback: true });
173
+ });
174
+ test("handles special characters in selected field values", async () => {
175
+ await db.transact(async (db) => {
176
+ await db.createOne("user", {
177
+ values: factory.user({
178
+ id: 1,
179
+ name: "O'Connor; DROP TABLE users;",
180
+ }),
181
+ });
182
+ const user = await db.findOne("user", {
183
+ select: ["id", "name"],
184
+ where: { id: 1 },
185
+ });
186
+ expect(user).toEqual({
187
+ id: 1,
188
+ name: "O'Connor; DROP TABLE users;",
189
+ });
190
+ }, { rollback: true });
191
+ });
192
+ test("handles large text values in selected fields", async () => {
193
+ await db.transact(async (db) => {
194
+ const longText = "a".repeat(10000);
195
+ await db.createOne("user", {
196
+ values: factory.user({ id: 1, name: longText }),
197
+ });
198
+ const user = await db.findOne("user", {
199
+ select: ["id", "name"],
200
+ where: { id: 1 },
201
+ });
202
+ expect(user).toEqual({ id: 1, name: longText });
203
+ }, { rollback: true });
204
+ });
205
+ });